<commit_before>/******************************************************************************************[Circ.h]
Copyright (c) 2007-2008, <NAME>

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**************************************************************************************************/

#ifndef Minisat_Circ_h
#define Minisat_Circ_h

#include "mtl/Queue.h"
#include "core/SolverTypes.h"
#include "circ/CircTypes.h"
#include "circ/Matching.h"
#include "circ/Normalization.h"

#include <cstdio>

namespace Minisat {

//=================================================================================================
// Circ -- a class for representing combinational circuits.


static const uint32_t pair_hash_prime = 1073741789;

class Circ
{
    // Types:
    struct GateData { Gate strash_next; Sig x, y; };
    typedef GMap<GateData> Gates;

    // Member variables:
    //
    Gates               gates;        // Gates[0] is reserved for the constant gate_True.
    GMap<uint8_t>       n_fanouts;

    unsigned int        n_inps;
    unsigned int        n_ands;
    Gate*               strash;
    unsigned int        strash_cap;
    vec<uint32_t>       gate_lim;

    Gate                tmp_gate;

    GSet                tmp_set;
    vec<Sig>            tmp_stack;
    GMap<int>           tmp_fanouts;
    
    // Private methods:
    //
    unsigned int allocId     ();
    GateType     idType      (unsigned int id) const;
    uint32_t     gateHash    (Gate g)          const;
    bool         gateEq      (Gate x, Gate y)  const;
    void         strashInsert(Gate g);
    Gate         strashFind  (Gate g)          const;
    void         strashRemove(Gate g);
    void         restrashAll ();

    Gate         gateFromId  (unsigned int id) const;

 public:
    // Mode of operation:
    //
    uint32_t rewrite_mode;

    Circ();

    // Misc. :
    //
    int  size  () const { return gates.size()-1; }
    int  nGates() const { return n_ands; }
    int  nInps () const { return n_inps; }
    int  nFanouts  (Gate g) const { return n_fanouts[g]; }
    void bumpFanout(Gate g) { n_fanouts[g]++; }

    // Environment state manipulation:
    //
    void clear  ();
    void moveTo (Circ& to);

    void push   ();
    void pop    ();
    void commit ();

    // Gate iterator:
    Gate nextGate (Gate g) const { assert(g != gate_Undef); uint32_t ind = index(g) + 1; return ind == (uint32_t)gates.size() ? gate_Undef : gateFromId(ind); }
    Gate firstGate()       const { return nextGate(gateFromId(0)); }
    Gate lastGate ()       const { return gateFromId(gates.size()-1); }

    // Node constructor functions:
    Sig mkInp    ();
    Sig mkAnd    (Sig x, Sig y, bool try_only = false);
    Sig mkOr     (Sig x, Sig y);
    Sig mkXorOdd (Sig x, Sig y);
    Sig mkXorEven(Sig x, Sig y);
    Sig mkXor    (Sig x, Sig y);
    Sig mkMuxOdd (Sig x, Sig y, Sig z);
    Sig mkMuxEven(Sig x, Sig y, Sig z);
    Sig mkMux    (Sig x, Sig y, Sig z);
    
    // Node inspection functions:
    Sig lchild(Gate g) const;
    Sig rchild(Gate g) const;
    Sig lchild(Sig x)  const;
    Sig rchild(Sig x)  const;

    // Pattern matching functions:
    bool matchMuxParts(Gate g, Gate h, Sig& x, Sig& y, Sig& z);
    bool matchMux (Gate g, Sig& x, Sig& y, Sig& z);
    bool matchXor (Gate g, Sig& x, Sig& y);
    bool matchXors(Gate g, vec<Sig>& xs);
    void matchAnds(Gate g, vec<Sig>& xs, bool match_muxes = false);
    void matchTwoLevel
                  (Gate g, vec<vec<Sig> >& xss, bool match_muxes = false);

    // Lookup whether different different patterns already exists somewhere:
    Sig tryAnd     (Sig x, Sig y);
    int costAnd    (Sig x, Sig y);
    int costXorOdd (Sig x, Sig y);
    int costXorEven(Sig x, Sig y);
    int costMuxOdd (Sig x, Sig y, Sig z);
    int costMuxEven(Sig x, Sig y, Sig z);

    // Debug
    void dump();
};


//=================================================================================================
// Box -- a class for storing inputs and outputs (roots/sinks) to a (sub) circuit:

struct Box {
    vec<Gate> inps;
    vec<Sig>  outs;

    void clear () { inps.clear(); outs.clear(); }
    void moveTo(Box& to){ inps.moveTo(to.inps); outs.moveTo(to.outs); }
    void copyTo(Box& to){ inps.copyTo(to.inps); outs.copyTo(to.outs); }
};

//=================================================================================================
// Flops -- a class for representing the sequential behaviour of a circuit:

class Flops {
    vec<Gate>  gates;
    GMap<Sig>  defs;
    SMap<char> is_def; // is_def[s] is true iff there exists a gate g such that defs[g] == s

 public:
    void clear()               { gates.clear(); defs.clear(); is_def.clear(); }
    void defineFlop(Gate f, Sig def){
        defs  .growTo(f,   sig_Undef);
        is_def.growTo(def, 0);

        gates.push(f);
        defs  [f]   = def;
        is_def[def] = 1; }

    bool isDef     (Sig x) const { return is_def.has(x) && is_def[x]; }
    bool isFlop    (Gate f)const { return defs.has(f) && (defs[f] != sig_Undef); }
    Sig  def       (Gate f)const { return defs[f]; }
    int  size      ()      const { return gates.size(); }
    Gate operator[](int i) const { return gates[i]; }

    void moveTo(Flops& to){ gates.moveTo(to.gates); defs.moveTo(to.defs); is_def.moveTo(to.is_def); }
    void copyTo(Flops& to) const { gates.copyTo(to.gates); defs.copyTo(to.defs); is_def.copyTo(to.is_def); }

    void map_ (const GMap<Sig>& m, Flops& to) const {
        to.clear();
        for (int i = 0; i < gates.size(); i++){
            Gate f   = gates[i];
            Sig  def = defs[f];
            assert(m[gate(def)] != sig_Undef);
            to.defineFlop(f, m[gate(def)] ^ sign(def));
        }
    }

    void comap(const GMap<Sig>& m, Flops& to) const {
        to.clear();
        for (int i = 0; i < gates.size(); i++){
            Gate f   = gates[i];
            Sig  def = defs[f];
            assert(m[f] != sig_Undef);
            assert(!sign(m[f]));
            to.defineFlop(gate(m[f]), def);
        }
    }

    void bimap (const GMap<Sig>& m, Flops& to) const {
        to.clear();
        for (int i = 0; i < gates.size(); i++){
            Gate f   = gates[i];
            Sig  def = defs[f];
            assert(m[f] != sig_Undef);
            assert(m[gate(def)] != sig_Undef);
            assert(!sign(m[f]));
            to.defineFlop(gate(m[f]), m[gate(def)] ^ sign(def));
        }
    }

};


//=================================================================================================
// Circ utility functions:


// Given certain values for inputs, calculate the values of all gates in the cone of influence
// of a signal:
bool evaluate(const Circ& c, Sig x, GMap<lbool>& values);

void bottomUpOrder(const Circ& c, Gate g, GSet& gset);
void bottomUpOrder(const Circ& c, Sig  x, GSet& gset);
void bottomUpOrder(const Circ& c, const vec<Gate>& gs, GSet& gset);
void bottomUpOrder(const Circ& c, const vec<Sig>&  xs, GSet& gset);
void bottomUpOrder(const Circ& c, const vec<Gate>& latches, const GMap<Sig>& latch_defs, GSet& gset);

Sig  copyGate(const Circ& src, Circ& dst, Gate g,      GMap<Sig>& copy_map);
Sig  copySig (const Circ& src, Circ& dst, Sig  x,      GMap<Sig>& copy_map);
void copySig (const Circ& src, Circ& dst, const vec<Sig>& xs, GMap<Sig>& copy_map);
void copyCirc(const Circ& src, Circ& dst, GMap<Sig>& map);

// FIXME: Move to CircTypes.
typedef vec<vec<Sig> > Eqs;

void copyCircWithSubst(const Circ& src, Circ& dst, GMap<Sig>& subst_map, GMap<Sig>& copy_map);
void normalizeEqs(Eqs& eqs);
void removeTrivialEqs(Eqs& eqs);
void makeSubstMap(const Circ& c, const Eqs& eqs, GMap<Sig>& m);

void circInfo(      Circ& c, Gate g, GSet& reachable, int& n_ands, int& n_xors, int& n_muxes, int& tot_ands);

 static inline
 void copy    (const Flops& from, Flops& to){ from.copyTo(to); }

//=================================================================================================
// Map functions:
//


static inline void map_ (const GMap<Sig>& m, Flops& flps){ Flops tmp; flps.map_(m, tmp); tmp.moveTo(flps); }
static inline void comap(const GMap<Sig>& m, Flops& flps){ Flops tmp; flps.comap(m, tmp); tmp.moveTo(flps); }
static inline void map  (const GMap<Sig>& m, Flops& flps){ Flops tmp; flps.bimap(m, tmp); tmp.moveTo(flps); }

static inline void map(const GMap<Sig>& m, Gate& g)    { if (g != gate_Undef) g = gate(m[g]); } // Use with care!
static inline void map(const GMap<Sig>& m, Sig&  x)    { if (x != sig_Undef) x = m[gate(x)] ^ sign(x); }
static inline void map(const GMap<Sig>& m, Box& b){
    for (int i = 0; i < b.inps.size(); i++){ assert(!sign(m[b.inps[i]])); b.inps[i] = gate(m[b.inps[i]]); }
    for (int i = 0; i < b.outs.size(); i++) b.outs[i] = m[gate(b.outs[i])] ^ sign(b.outs[i]);
}


template<class T>
static inline void map(const GMap<Sig>& m, vec<T>& xs){
    for (int i = 0; i < xs.size(); i++)
        map(m, xs[i]);
}

// Haskellish type: C -> (Sig A -> Sig B) -> (Sig C -> F (Sig A)) -> (Sig C -> F (Sig B))
template<class T>
static inline
void map(const GMap<Sig>& m, GMap<T>& tm){
    typename GMap<T>::iterator it;
    for (it = tm.begin(); it != tm.end(); ++it)
        map(m, *it);
}

#if 0
// FIXME: needs to be thought through.

// Haskellish type: A -> (Sig A -> Sig B) -> (Sig A -> C) -> (Sig B -> C)
template<class T>
static inline
void comap(const Circ& c, const GMap<Sig>& m, GMap<T>& tm){
    GMap<T> tmp; tm.copyTo(tmp);

    tm.clear(); // Changes "type" from (Sig A -> Sig C) to (Sig B -> Sig C)

    for (Gate g = c.firstGate(); g != gate_Undef; g = c.nextGate(g))
        if (m[g] == sig_Undef){<commit_msg>Bugfix: the general kind of map for GMap's was not safe.<commit_after>/******************************************************************************************[Circ.h]
Copyright (c) 2007-2008, <NAME>

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**************************************************************************************************/

#ifndef Minisat_Circ_h
#define Minisat_Circ_h

#include "mtl/Queue.h"
#include "core/SolverTypes.h"
#include "circ/CircTypes.h"
#include "circ/Matching.h"
#include "circ/Normalization.h"

#include <cstdio>

namespace Minisat {

//=================================================================================================
// Circ -- a class for representing combinational circuits.


static const uint32_t pair_hash_prime = 1073741789;

class Circ
{
    // Types:
    struct GateData { Gate strash_next; Sig x, y; };
    typedef GMap<GateData> Gates;

    // Member variables:
    //
    Gates               gates;        // Gates[0] is reserved for the constant gate_True.
    GMap<uint8_t>       n_fanouts;

    unsigned int        n_inps;
    unsigned int        n_ands;
    Gate*               strash;
    unsigned int        strash_cap;
    vec<uint32_t>       gate_lim;

    Gate                tmp_gate;

    GSet                tmp_set;
    vec<Sig>            tmp_stack;
    GMap<int>           tmp_fanouts;
    
    // Private methods:
    //
    unsigned int allocId     ();
    GateType     idType      (unsigned int id) const;
    uint32_t     gateHash    (Gate g)          const;
    bool         gateEq      (Gate x, Gate y)  const;
    void         strashInsert(Gate g);
    Gate         strashFind  (Gate g)          const;
    void         strashRemove(Gate g);
    void         restrashAll ();

    Gate         gateFromId  (unsigned int id) const;

 public:
    // Mode of operation:
    //
    uint32_t rewrite_mode;

    Circ();

    // Misc. :
    //
    int  size  () const { return gates.size()-1; }
    int  nGates() const { return n_ands; }
    int  nInps () const { return n_inps; }
    int  nFanouts  (Gate g) const { return n_fanouts[g]; }
    void bumpFanout(Gate g) { n_fanouts[g]++; }

    // Environment state manipulation:
    //
    void clear  ();
    void moveTo (Circ& to);

    void push   ();
    void pop    ();
    void commit ();

    // Gate iterator:
    Gate nextGate (Gate g) const { assert(g != gate_Undef); uint32_t ind = index(g) + 1; return ind == (uint32_t)gates.size() ? gate_Undef : gateFromId(ind); }
    Gate firstGate()       const { return nextGate(gateFromId(0)); }
    Gate lastGate ()       const { return gateFromId(gates.size()-1); }

    // Node constructor functions:
    Sig mkInp    ();
    Sig mkAnd    (Sig x, Sig y, bool try_only = false);
    Sig mkOr     (Sig x, Sig y);
    Sig mkXorOdd (Sig x, Sig y);
    Sig mkXorEven(Sig x, Sig y);
    Sig mkXor    (Sig x, Sig y);
    Sig mkMuxOdd (Sig x, Sig y, Sig z);
    Sig mkMuxEven(Sig x, Sig y, Sig z);
    Sig mkMux    (Sig x, Sig y, Sig z);
    
    // Node inspection functions:
    Sig lchild(Gate g) const;
    Sig rchild(Gate g) const;
    Sig lchild(Sig x)  const;
    Sig rchild(Sig x)  const;

    // Pattern matching functions:
    bool matchMuxParts(Gate g, Gate h, Sig& x, Sig& y, Sig& z);
    bool matchMux (Gate g, Sig& x, Sig& y, Sig& z);
    bool matchXor (Gate g, Sig& x, Sig& y);
    bool matchXors(Gate g, vec<Sig>& xs);
    void matchAnds(Gate g, vec<Sig>& xs, bool match_muxes = false);
    void matchTwoLevel
                  (Gate g, vec<vec<Sig> >& xss, bool match_muxes = false);

    // Lookup whether different different patterns already exists somewhere:
    Sig tryAnd     (Sig x, Sig y);
    int costAnd    (Sig x, Sig y);
    int costXorOdd (Sig x, Sig y);
    int costXorEven(Sig x, Sig y);
    int costMuxOdd (Sig x, Sig y, Sig z);
    int costMuxEven(Sig x, Sig y, Sig z);

    // Debug
    void dump();
};


//=================================================================================================
// Box -- a class for storing inputs and outputs (roots/sinks) to a (sub) circuit:

struct Box {
    vec<Gate> inps;
    vec<Sig>  outs;

    void clear () { inps.clear(); outs.clear(); }
    void moveTo(Box& to){ inps.moveTo(to.inps); outs.moveTo(to.outs); }
    void copyTo(Box& to){ inps.copyTo(to.inps); outs.copyTo(to.outs); }
};

//=================================================================================================
// Flops -- a class for representing the sequential behaviour of a circuit:

class Flops {
    vec<Gate>  gates;
    GMap<Sig>  defs;
    SMap<char> is_def; // is_def[s] is true iff there exists a gate g such that defs[g] == s

 public:
    void clear()               { gates.clear(); defs.clear(); is_def.clear(); }
    void defineFlop(Gate f, Sig def){
        defs  .growTo(f,   sig_Undef);
        is_def.growTo(def, 0);

        gates.push(f);
        defs  [f]   = def;
        is_def[def] = 1; }

    bool isDef     (Sig x) const { return is_def.has(x) && is_def[x]; }
    bool isFlop    (Gate f)const { return defs.has(f) && (defs[f] != sig_Undef); }
    Sig  def       (Gate f)const { return defs[f]; }
    int  size      ()      const { return gates.size(); }
    Gate operator[](int i) const { return gates[i]; }

    void moveTo(Flops& to){ gates.moveTo(to.gates); defs.moveTo(to.defs); is_def.moveTo(to.is_def); }
    void copyTo(Flops& to) const { gates.copyTo(to.gates); defs.copyTo(to.defs); is_def.copyTo(to.is_def); }

    void map_ (const GMap<Sig>& m, Flops& to) const {
        to.clear();
        for (int i = 0; i < gates.size(); i++){
            Gate f   = gates[i];
            Sig  def = defs[f];
            assert(m[gate(def)] != sig_Undef);
            to.defineFlop(f, m[gate(def)] ^ sign(def));
        }
    }

    void comap(const GMap<Sig>& m, Flops& to) const {
        to.clear();
        for (int i = 0; i < gates.size(); i++){
            Gate f   = gates[i];
            Sig  def = defs[f];
            assert(m[f] != sig_Undef);
            assert(!sign(m[f]));
            to.defineFlop(gate(m[f]), def);
        }
    }

    void bimap (const GMap<Sig>& m, Flops& to) const {
        to.clear();
        for (int i = 0; i < gates.size(); i++){
            Gate f   = gates[i];
            Sig  def = defs[f];
            assert(m[f] != sig_Undef);
            assert(m[gate(def)] != sig_Undef);
            assert(!sign(m[f]));
            to.defineFlop(gate(m[f]), m[gate(def)] ^ sign(def));
        }
    }

};


//=================================================================================================
// Circ utility functions:


// Given certain values for inputs, calculate the values of all gates in the cone of influence
// of a signal:
bool evaluate(const Circ& c, Sig x, GMap<lbool>& values);

void bottomUpOrder(const Circ& c, Gate g, GSet& gset);
void bottomUpOrder(const Circ& c, Sig  x, GSet& gset);
void bottomUpOrder(const Circ& c, const vec<Gate>& gs, GSet& gset);
void bottomUpOrder(const Circ& c, const vec<Sig>&  xs, GSet& gset);
void bottomUpOrder(const Circ& c, const vec<Gate>& latches, const GMap<Sig>& latch_defs, GSet& gset);

Sig  copyGate(const Circ& src, Circ& dst, Gate g,      GMap<Sig>& copy_map);
Sig  copySig (const Circ& src, Circ& dst, Sig  x,      GMap<Sig>& copy_map);
void copySig (const Circ& src, Circ& dst, const vec<Sig>& xs, GMap<Sig>& copy_map);
void copyCirc(const Circ& src, Circ& dst, GMap<Sig>& map);

// FIXME: Move to CircTypes.
typedef vec<vec<Sig> > Eqs;

void copyCircWithSubst(const Circ& src, Circ& dst, GMap<Sig>& subst_map, GMap<Sig>& copy_map);
void normalizeEqs(Eqs& eqs);
void removeTrivialEqs(Eqs& eqs);
void makeSubstMap(const Circ& c, const Eqs& eqs, GMap<Sig>& m);

void circInfo(      Circ& c, Gate g, GSet& reachable, int& n_ands, int& n_xors, int& n_muxes, int& tot_ands);

 static inline
 void copy    (const Flops& from, Flops& to){ from.copyTo(to); }

//=================================================================================================
// Map functions:
//


static inline void map_ (const GMap<Sig>& m, Flops& flps){ Flops tmp; flps.map_(m, tmp); tmp.moveTo(flps); }
static inline void comap(const GMap<Sig>& m, Flops& flps){ Flops tmp; flps.comap(m, tmp); tmp.moveTo(flps); }
static inline void map  (const GMap<Sig>& m, Flops& flps){ Flops tmp; flps.bimap(m, tmp); tmp.moveTo(flps); }

static inline void map(const GMap<Sig>& m, Gate& g)    { if (g != gate_Undef) g = gate(m[g]); } // Use with care!
static inline void map(const GMap<Sig>& m, Sig&  x)    { if (x != sig_Undef) x = m[gate(x)] ^ sign(x); }
static inline void map(const GMap<Sig>& m, Box& b){
    for (int i = 0; i < b.inps.size(); i++){ assert(!sign(m[b.inps[i]])); b.inps[i] = gate(m[b.inps[i]]); }
    for (int i = 0; i < b.outs.size(); i++) b.outs[i] = m[gate(b.outs[i])] ^ sign(b.outs[i]);
}


template<class T>
static inline void map(const GMap<Sig>& m, vec<T>& xs){
    for (int i = 0; i < xs.size(); i++)
        map(m, xs[i]);
}

static inline
void map(const GMap<Sig>& m, GMap<Sig>& tm){
    GMap<Sig>::iterator it;
    for (it = tm.begin(); it != tm.end(); ++it)
        if (m.has(gate(*it)))
            map(m, *it);
        else
            *it = sig_Undef;
}

#if 0
// NOTE: this version of map does not work when there is some key in 'tm' that does not exists in
// 'm'. It would be resonable for the user to provide a default T value, or use T's default
// constructor, but I'll leave that for later.
// NOTE: Haskellish type: C -> (Sig A -> Sig B) -> (Sig C -> F (Sig A)) -> (Sig C -> F (Sig B))
template<class T>
static inline
void map(const GMap<Sig>& m, GMap<T>& tm){
    typename GMap<T>::iterator it;
    for (it = tm.begin(); it != tm.end(); ++it)
        map(m, *it);
}
#endif


#if 0
// FIXME: needs to be thought through.

// Haskellish type: A -> (Sig A -> Sig B) -> (Sig A -> C) -> (Sig B -> C)
template<class T>
static inline
void comap(const Circ& c, const GMap<Sig>& m, GMap<T>& tm){
    GMap<T> tmp; tm.copyTo(tmp);

    tm.clear(); // Changes "type" from (Sig A -> Sig C) to (Sig B -> Sig C)

    for (Gate g = c.firstGate(); g != gate_Undef; g = c.nextGate(g))
        if (m[g] == sig_Undef){
{'fraction_non_alphanumeric': 0.19241179978896178, 'fraction_numerical': 0.0041748864522640735, 'mean_word_length': 2.874511198009243, 'pattern_counts': {'":': 0, '<': 120, '<?xml version=': 0, '>': 136, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '686800', 'n_tokens_mistral': 7412, 'n_tokens_neox': 7134, 'n_words': 2391}