| /**CFile**************************************************************** |
| |
| FileName [abcSaucy.c] |
| |
| SystemName [ABC: Logic synthesis and verification system.] |
| |
| PackageName [Symmetry Detection Package.] |
| |
| Synopsis [Finds symmetries under permutation (but not negation) of I/Os.] |
| |
| Author [Hadi Katebi] |
| |
| Affiliation [University of Michigan] |
| |
| Date [Ver. 1.0. Started - April, 2012.] |
| |
| Revision [No revisions so far] |
| |
| Comments [] |
| |
| Debugging [There are some part of the code that are commented out. Those parts mostly print |
| the contents of the data structures to the standard output. Un-comment them if you |
| find them useful for debugging.] |
| |
| ***********************************************************************/ |
| |
| #include "base/abc/abc.h" |
| #include "opt/sim/sim.h" |
| |
| ABC_NAMESPACE_IMPL_START |
| |
| /* on/off switches */ |
| #define REFINE_BY_SIM_1 0 |
| #define REFINE_BY_SIM_2 0 |
| #define BACKTRACK_BY_SAT 1 |
| #define SELECT_DYNAMICALLY 0 |
| |
| /* number of iterations for sim1 and sim2 refinements */ |
| int NUM_SIM1_ITERATION; |
| int NUM_SIM2_ITERATION; |
| |
| /* conflict analysis */ |
| #define CLAUSE_DECAY 0.9 |
| #define MAX_LEARNTS 50 |
| |
| /* |
| * saucy.c |
| * |
| * by Paul T. Darga <pdarga@umich.edu> |
| * and Mark Liffiton <liffiton@umich.edu> |
| * and Hadi Katebi <hadik@eecs.umich.edu> |
| * |
| * Copyright (C) 2004, The Regents of the University of Michigan |
| * See the LICENSE file for details. |
| */ |
| |
| struct saucy_stats { |
| double grpsize_base; |
| int grpsize_exp; |
| int levels; |
| int nodes; |
| int bads; |
| int gens; |
| int support; |
| }; |
| |
| struct saucy_graph { |
| int n; |
| int e; |
| int *adj; |
| int *edg; |
| }; |
| |
| struct coloring { |
| int *lab; /* Labelling of objects */ |
| int *unlab; /* Inverse of lab */ |
| int *cfront; /* Pointer to front of cells */ |
| int *clen; /* Length of cells (defined for cfront's) */ |
| }; |
| |
| struct sim_result { |
| int *inVec; |
| int *outVec; |
| int inVecSignature; |
| int outVecOnes; |
| double activity; |
| }; |
| |
| struct saucy { |
| /* Graph data */ |
| int n; /* Size of domain */ |
| int *adj; /* Neighbors of k: edg[adj[k]]..edg[adj[k+1]] */ |
| int *edg; /* Actual neighbor data */ |
| int *dadj; /* Fanin neighbor indices, for digraphs */ |
| int *dedg; /* Fanin neighbor data, for digraphs */ |
| |
| /* Coloring data */ |
| struct coloring left, right; |
| int *nextnon; /* Forward next-nonsingleton pointers */ |
| int *prevnon; /* Backward next-nonsingleton pointers */ |
| |
| /* Refinement: inducers */ |
| char *indmark; /* Induce marks */ |
| int *ninduce; /* Nonsingletons that might induce refinement */ |
| int *sinduce; /* Singletons that might induce refinement */ |
| int nninduce; /* Size of ninduce stack */ |
| int nsinduce; /* Size of sinduce stack */ |
| |
| /* Refinement: marked cells */ |
| int *clist; /* List of cells marked for refining */ |
| int csize; /* Number of cells in clist */ |
| |
| /* Refinement: workspace */ |
| char *stuff; /* Bit vector, but one char per bit */ |
| int *ccount; /* Number of connections to refining cell */ |
| int *bucket; /* Workspace */ |
| int *count; /* Num vertices with same adj count to ref cell */ |
| int *junk; /* More workspace */ |
| int *gamma; /* Working permutation */ |
| int *conncnts; /* Connection counts for cell fronts */ |
| |
| /* Search data */ |
| int lev; /* Current search tree level */ |
| int anc; /* Level of greatest common ancestor with zeta */ |
| int *anctar; /* Copy of target cell at anc */ |
| int kanctar; /* Location within anctar to iterate from */ |
| int *start; /* Location of target at each level */ |
| int indmin; /* Used for group size computation */ |
| int match; /* Have we not diverged from previous left? */ |
| |
| /* Search: orbit partition */ |
| int *theta; /* Running approximation of orbit partition */ |
| int *thsize; /* Size of cells in theta, defined for mcrs */ |
| int *thnext; /* Next rep in list (circular list) */ |
| int *thprev; /* Previous rep in list */ |
| int *threp; /* First rep for a given cell front */ |
| int *thfront; /* The cell front associated with this rep */ |
| |
| /* Search: split record */ |
| int *splitvar; /* The actual value of the splits on the left-most branch */ |
| int *splitwho; /* List of where splits occurred */ |
| int *splitfrom; /* List of cells which were split */ |
| int *splitlev; /* Where splitwho/from begins for each level */ |
| int nsplits; /* Number of splits at this point */ |
| |
| /* Search: differences from leftmost */ |
| char *diffmark; /* Marked for diff labels */ |
| int *diffs; /* List of diff labels */ |
| int *difflev; /* How many labels diffed at each level */ |
| int ndiffs; /* Current number of diffs */ |
| int *undifflev; /* How many diff labels fixed at each level */ |
| int nundiffs; /* Current number of diffs in singletons (fixed) */ |
| int *unsupp; /* Inverted diff array */ |
| int *specmin; /* Speculated mappings */ |
| int *pairs; /* Not-undiffed diffs that can make two-cycles */ |
| int *unpairs; /* Indices into pairs */ |
| int npairs; /* Number of such pairs */ |
| int *diffnons; /* Diffs that haven't been undiffed */ |
| int *undiffnons; /* Inverse of that */ |
| int ndiffnons; /* Number of such diffs */ |
| |
| /* Polymorphic functions */ |
| int (*split)(struct saucy *, struct coloring *, int, int); |
| int (*is_automorphism)(struct saucy *); |
| int (*ref_singleton)(struct saucy *, struct coloring *, int); |
| int (*ref_nonsingle)(struct saucy *, struct coloring *, int); |
| void (*select_decomposition)(struct saucy *, int *, int *, int *); |
| |
| /* Statistics structure */ |
| struct saucy_stats *stats; |
| |
| /* New data structures for Boolean formulas */ |
| Abc_Ntk_t * pNtk; |
| Abc_Ntk_t * pNtk_permuted; |
| int * depAdj; |
| int * depEdg; |
| Vec_Int_t ** iDep, ** oDep; |
| Vec_Int_t ** obs, ** ctrl; |
| Vec_Ptr_t ** topOrder; |
| Vec_Ptr_t * randomVectorArray_sim1; |
| int * randomVectorSplit_sim1; |
| Vec_Ptr_t * randomVectorArray_sim2; |
| int * randomVectorSplit_sim2; |
| char * marks; |
| int * pModel; |
| Vec_Ptr_t * satCounterExamples; |
| double activityInc; |
| |
| int fBooleanMatching; |
| int fPrintTree; |
| int fLookForSwaps; |
| FILE * gFile; |
| |
| int (*refineBySim1)(struct saucy *, struct coloring *); |
| int (*refineBySim2)(struct saucy *, struct coloring *); |
| int (*print_automorphism)(FILE *f, int n, const int *gamma, int nsupp, const int *support, char * marks, Abc_Ntk_t * pNtk); |
| }; |
| |
| static int *ints(int n) { return ABC_ALLOC(int, n); } |
| static int *zeros(int n) { return ABC_CALLOC(int, n); } |
| static char *bits(int n) { return ABC_CALLOC(char, n); } |
| |
| static char * getVertexName(Abc_Ntk_t *pNtk, int v); |
| static int * generateProperInputVector(Abc_Ntk_t * pNtk, struct coloring *c, Vec_Int_t * randomVector); |
| static int ifInputVectorsAreConsistent(struct saucy * s, int * leftVec, int * rightVec); |
| static int ifOutputVectorsAreConsistent(struct saucy * s, int * leftVec, int * rightVec); |
| static Vec_Ptr_t ** findTopologicalOrder(Abc_Ntk_t * pNtk); |
| static void getDependencies(Abc_Ntk_t *pNtk, Vec_Int_t** iDep, Vec_Int_t** oDep); |
| static struct saucy_graph * buildDepGraph (Abc_Ntk_t *pNtk, Vec_Int_t ** iDep, Vec_Int_t ** oDep); |
| static struct saucy_graph * buildSim1Graph(Abc_Ntk_t * pNtk, struct coloring *c, Vec_Int_t * randVec, Vec_Int_t ** iDep, Vec_Int_t ** oDep); |
| static struct saucy_graph * buildSim2Graph(Abc_Ntk_t * pNtk, struct coloring *c, Vec_Int_t * randVec, Vec_Int_t ** iDep, Vec_Int_t ** oDep, Vec_Ptr_t ** topOrder, Vec_Int_t ** obs, Vec_Int_t ** ctrl); |
| static Vec_Int_t * assignRandomBitsToCells(Abc_Ntk_t * pNtk, struct coloring *c); |
| static int Abc_NtkCecSat_saucy(Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, int * pModel); |
| static struct sim_result * analyzeConflict(Abc_Ntk_t * pNtk, int * pModel, int fVerbose); |
| static void bumpActivity (struct saucy * s, struct sim_result * cex); |
| static void reduceDB(struct saucy * s); |
| |
| |
| static int |
| print_automorphism_ntk(FILE *f, int n, const int *gamma, int nsupp, const int *support, char * marks, Abc_Ntk_t * pNtk) |
| { |
| int i, j, k; |
| |
| /* We presume support is already sorted */ |
| for (i = 0; i < nsupp; ++i) { |
| k = support[i]; |
| |
| /* Skip elements already seen */ |
| if (marks[k]) continue; |
| |
| /* Start an orbit */ |
| marks[k] = 1; |
| fprintf(f, "(%s", getVertexName(pNtk, k)); |
| |
| /* Mark and notify elements in this orbit */ |
| for (j = gamma[k]; j != k; j = gamma[j]) { |
| marks[j] = 1; |
| fprintf(f, " %s", getVertexName(pNtk, j)); |
| } |
| |
| /* Finish off the orbit */ |
| fprintf(f, ")"); |
| } |
| fprintf(f, "\n"); |
| |
| /* Clean up after ourselves */ |
| for (i = 0; i < nsupp; ++i) { |
| marks[support[i]] = 0; |
| } |
| |
| return 1; |
| } |
| |
| static int |
| print_automorphism_ntk2(FILE *f, int n, const int *gamma, int nsupp, const int *support, char * marks, Abc_Ntk_t * pNtk) |
| { |
| int i, j, k; |
| |
| /* We presume support is already sorted */ |
| for (i = 0; i < nsupp; ++i) { |
| k = support[i]; |
| |
| /* Skip elements already seen */ |
| if (marks[k]) continue; |
| |
| /* Start an orbit */ |
| marks[k] = 1; |
| fprintf(f, "%d", k-1); |
| |
| /* Mark and notify elements in this orbit */ |
| for (j = gamma[k]; j != k; j = gamma[j]) { |
| marks[j] = 1; |
| fprintf(f, " %d ", j-1); |
| } |
| |
| /* Finish off the orbit */ |
| } |
| fprintf(f, "-1\n"); |
| |
| /* Clean up after ourselves */ |
| for (i = 0; i < nsupp; ++i) { |
| marks[support[i]] = 0; |
| } |
| |
| return 1; |
| } |
| |
| static int |
| print_automorphism_quiet(FILE *f, int n, const int *gamma, int nsupp, const int *support, char * marks, Abc_Ntk_t * pNtk) |
| { |
| return 1; |
| } |
| |
| static int |
| array_find_min(const int *a, int n) |
| { |
| const int *start = a, *end = a + n, *min = a; |
| while (++a != end) { |
| if (*a < *min) min = a; |
| } |
| return min - start; |
| } |
| |
| static void |
| swap(int *a, int x, int y) |
| { |
| int tmp = a[x]; |
| a[x] = a[y]; |
| a[y] = tmp; |
| } |
| |
| static void |
| sift_up(int *a, int k) |
| { |
| int p; |
| do { |
| p = k / 2; |
| if (a[k] <= a[p]) { |
| return; |
| } |
| else { |
| swap(a, k, p); |
| k = p; |
| } |
| } while (k > 1); |
| } |
| |
| static void |
| sift_down(int *a, int n) |
| { |
| int p = 1, k = 2; |
| while (k <= n) { |
| if (k < n && a[k] < a[k+1]) ++k; |
| if (a[p] < a[k]) { |
| swap(a, p, k); |
| p = k; |
| k = 2 * p; |
| } |
| else { |
| return; |
| } |
| } |
| } |
| |
| static void |
| heap_sort(int *a, int n) |
| { |
| int i; |
| for (i = 1; i < n; ++i) { |
| sift_up(a-1, i+1); |
| } |
| --i; |
| while (i > 0) { |
| swap(a, 0, i); |
| sift_down(a-1, i--); |
| } |
| } |
| |
| static void |
| insertion_sort(int *a, int n) |
| { |
| int i, j, k; |
| for (i = 1; i < n; ++i) { |
| k = a[i]; |
| for (j = i; j > 0 && a[j-1] > k; --j) { |
| a[j] = a[j-1]; |
| } |
| a[j] = k; |
| } |
| } |
| |
| static int |
| partition(int *a, int n, int m) |
| { |
| int f = 0, b = n; |
| for (;;) { |
| while (a[f] <= m) ++f; |
| do --b; while (m <= a[b]); |
| if (f < b) { |
| swap(a, f, b); |
| ++f; |
| } |
| else break; |
| } |
| return f; |
| } |
| |
| static int |
| log_base2(int n) |
| { |
| int k = 0; |
| while (n > 1) { |
| ++k; |
| n >>= 1; |
| } |
| return k; |
| } |
| |
| static int |
| median(int a, int b, int c) |
| { |
| if (a <= b) { |
| if (b <= c) return b; |
| if (a <= c) return c; |
| return a; |
| } |
| else { |
| if (a <= c) return a; |
| if (b <= c) return c; |
| return b; |
| } |
| } |
| |
| static void |
| introsort_loop(int *a, int n, int lim) |
| { |
| int p; |
| while (n > 16) { |
| if (lim == 0) { |
| heap_sort(a, n); |
| return; |
| } |
| --lim; |
| p = partition(a, n, median(a[0], a[n/2], a[n-1])); |
| introsort_loop(a + p, n - p, lim); |
| n = p; |
| } |
| } |
| |
| static void |
| introsort(int *a, int n) |
| { |
| introsort_loop(a, n, 2 * log_base2(n)); |
| insertion_sort(a, n); |
| } |
| |
| static int |
| do_find_min(struct coloring *c, int t) |
| { |
| return array_find_min(c->lab + t, c->clen[t] + 1) + t; |
| } |
| |
| static int |
| find_min(struct saucy *s, int t) |
| { |
| return do_find_min(&s->right, t); |
| } |
| |
| static void |
| set_label(struct coloring *c, int index, int value) |
| { |
| c->lab[index] = value; |
| c->unlab[value] = index; |
| } |
| |
| static void |
| swap_labels(struct coloring *c, int a, int b) |
| { |
| int tmp = c->lab[a]; |
| set_label(c, a, c->lab[b]); |
| set_label(c, b, tmp); |
| } |
| |
| static void |
| move_to_back(struct saucy *s, struct coloring *c, int k) |
| { |
| int cf = c->cfront[k]; |
| int cb = cf + c->clen[cf]; |
| int offset = s->conncnts[cf]++; |
| |
| /* Move this connected label to the back of its cell */ |
| swap_labels(c, cb - offset, c->unlab[k]); |
| |
| /* Add it to the cell list if it's the first one swapped */ |
| if (!offset) s->clist[s->csize++] = cf; |
| } |
| |
| static void |
| data_mark(struct saucy *s, struct coloring *c, int k) |
| { |
| int cf = c->cfront[k]; |
| |
| /* Move connects to the back of nonsingletons */ |
| if (c->clen[cf]) move_to_back(s, c, k); |
| } |
| |
| static void |
| data_count(struct saucy *s, struct coloring *c, int k) |
| { |
| int cf = c->cfront[k]; |
| |
| /* Move to back and count the number of connections */ |
| if (c->clen[cf] && !s->ccount[k]++) move_to_back(s, c, k); |
| } |
| |
| static int |
| check_mapping(struct saucy *s, const int *adj, const int *edg, int k) |
| { |
| int i, gk, ret = 1; |
| |
| /* Mark gamma of neighbors */ |
| for (i = adj[k]; i != adj[k+1]; ++i) { |
| s->stuff[s->gamma[edg[i]]] = 1; |
| } |
| |
| /* Check neighbors of gamma */ |
| gk = s->gamma[k]; |
| for (i = adj[gk]; ret && i != adj[gk+1]; ++i) { |
| ret = s->stuff[edg[i]]; |
| } |
| |
| /* Clear out bit vector before we leave */ |
| for (i = adj[k]; i != adj[k+1]; ++i) { |
| s->stuff[s->gamma[edg[i]]] = 0; |
| } |
| |
| return ret; |
| } |
| |
| static int |
| add_conterexample(struct saucy *s, struct sim_result * cex) |
| { |
| int i; |
| int nins = Abc_NtkPiNum(s->pNtk); |
| struct sim_result * savedcex; |
| |
| cex->inVecSignature = 0; |
| for (i = 0; i < nins; i++) { |
| if (cex->inVec[i]) { |
| cex->inVecSignature += (cex->inVec[i] * i * i); |
| cex->inVecSignature ^= 0xABCD; |
| } |
| } |
| |
| for (i = 0; i < Vec_PtrSize(s->satCounterExamples); i++) { |
| savedcex = (struct sim_result *)Vec_PtrEntry(s->satCounterExamples, i); |
| if (savedcex->inVecSignature == cex->inVecSignature) { |
| //bumpActivity(s, savedcex); |
| return 0; |
| } |
| } |
| |
| Vec_PtrPush(s->satCounterExamples, cex); |
| bumpActivity(s, cex); |
| return 1; |
| } |
| |
| static int |
| is_undirected_automorphism(struct saucy *s) |
| { |
| int i, j, ret; |
| |
| for (i = 0; i < s->ndiffs; ++i) { |
| j = s->unsupp[i]; |
| if (!check_mapping(s, s->adj, s->edg, j)) return 0; |
| } |
| |
| ret = Abc_NtkCecSat_saucy(s->pNtk, s->pNtk_permuted, s->pModel); |
| |
| if( BACKTRACK_BY_SAT && !ret ) { |
| struct sim_result * cex; |
| |
| cex = analyzeConflict( s->pNtk, s->pModel, s->fPrintTree ); |
| add_conterexample(s, cex); |
| |
| cex = analyzeConflict( s->pNtk_permuted, s->pModel, s->fPrintTree ); |
| add_conterexample(s, cex); |
| |
| s->activityInc *= (1 / CLAUSE_DECAY); |
| if (Vec_PtrSize(s->satCounterExamples) >= MAX_LEARNTS) |
| reduceDB(s); |
| } |
| |
| return ret; |
| } |
| |
| static int |
| is_directed_automorphism(struct saucy *s) |
| { |
| int i, j; |
| |
| for (i = 0; i < s->ndiffs; ++i) { |
| j = s->unsupp[i]; |
| if (!check_mapping(s, s->adj, s->edg, j)) return 0; |
| if (!check_mapping(s, s->dadj, s->dedg, j)) return 0; |
| } |
| return 1; |
| } |
| |
| static void |
| add_induce(struct saucy *s, struct coloring *c, int who) |
| { |
| if (!c->clen[who]) { |
| s->sinduce[s->nsinduce++] = who; |
| } |
| else { |
| s->ninduce[s->nninduce++] = who; |
| } |
| s->indmark[who] = 1; |
| } |
| |
| static void |
| fix_fronts(struct coloring *c, int cf, int ff) |
| { |
| int i, end = cf + c->clen[cf]; |
| for (i = ff; i <= end; ++i) { |
| c->cfront[c->lab[i]] = cf; |
| } |
| } |
| |
| static void |
| array_indirect_sort(int *a, const int *b, int n) |
| { |
| int h, i, j, k; |
| |
| /* Shell sort, as implemented in nauty, (C) Brendan McKay */ |
| j = n / 3; |
| h = 1; |
| do { h = 3 * h + 1; } while (h < j); |
| |
| do { |
| for (i = h; i < n; ++i) { |
| k = a[i]; |
| for (j = i; b[a[j-h]] > b[k]; ) { |
| a[j] = a[j-h]; |
| if ((j -= h) < h) break; |
| } |
| a[j] = k; |
| } |
| h /= 3; |
| } while (h > 0); |
| } |
| |
| static int |
| at_terminal(struct saucy *s) |
| { |
| return s->nsplits == s->n; |
| } |
| |
| static void |
| add_diffnon(struct saucy *s, int k) |
| { |
| /* Only add if we're in a consistent state */ |
| if (s->ndiffnons == -1) return; |
| |
| s->undiffnons[k] = s->ndiffnons; |
| s->diffnons[s->ndiffnons++] = k; |
| } |
| |
| static void |
| remove_diffnon(struct saucy *s, int k) |
| { |
| int j; |
| |
| if (s->undiffnons[k] == -1) return; |
| |
| j = s->diffnons[--s->ndiffnons]; |
| s->diffnons[s->undiffnons[k]] = j; |
| s->undiffnons[j] = s->undiffnons[k]; |
| |
| s->undiffnons[k] = -1; |
| } |
| |
| static void |
| add_diff(struct saucy *s, int k) |
| { |
| if (!s->diffmark[k]) { |
| s->diffmark[k] = 1; |
| s->diffs[s->ndiffs++] = k; |
| add_diffnon(s, k); |
| } |
| } |
| |
| static int |
| is_a_pair(struct saucy *s, int k) |
| { |
| return s->unpairs[k] != -1; |
| } |
| |
| static int |
| in_cell_range(struct coloring *c, int ff, int cf) |
| { |
| int cb = cf + c->clen[cf]; |
| return cf <= ff && ff <= cb; |
| } |
| |
| static void |
| add_pair(struct saucy *s, int k) |
| { |
| if (s->npairs != -1) { |
| s->unpairs[k] = s->npairs; |
| s->pairs[s->npairs++] = k; |
| } |
| } |
| |
| static void |
| eat_pair(struct saucy *s, int k) |
| { |
| int j; |
| j = s->pairs[--s->npairs]; |
| s->pairs[s->unpairs[k]] = j; |
| s->unpairs[j] = s->unpairs[k]; |
| s->unpairs[k] = -1; |
| } |
| |
| static void |
| pick_all_the_pairs(struct saucy *s) |
| { |
| int i; |
| for (i = 0; i < s->npairs; ++i) { |
| s->unpairs[s->pairs[i]] = -1; |
| } |
| s->npairs = 0; |
| } |
| |
| static void |
| clear_undiffnons(struct saucy *s) |
| { |
| int i; |
| for (i = 0 ; i < s->ndiffnons ; ++i) { |
| s->undiffnons[s->diffnons[i]] = -1; |
| } |
| } |
| |
| static void |
| fix_diff_singleton(struct saucy *s, int cf) |
| { |
| int r = s->right.lab[cf]; |
| int l = s->left.lab[cf]; |
| int rcfl; |
| |
| if (!s->right.clen[cf] && r != l) { |
| |
| /* Make sure diff is marked */ |
| add_diff(s, r); |
| |
| /* It is now undiffed since it is singleton */ |
| ++s->nundiffs; |
| remove_diffnon(s, r); |
| |
| /* Mark the other if not singleton already */ |
| rcfl = s->right.cfront[l]; |
| if (s->right.clen[rcfl]) { |
| add_diff(s, l); |
| |
| /* Check for pairs */ |
| if (in_cell_range(&s->right, s->left.unlab[r], rcfl)) { |
| add_pair(s, l); |
| } |
| } |
| /* Otherwise we might be eating a pair */ |
| else if (is_a_pair(s, r)) { |
| eat_pair(s, r); |
| } |
| } |
| } |
| |
| static void |
| fix_diff_subtract(struct saucy *s, int cf, const int *a, const int *b) |
| { |
| int i, k; |
| int cb = cf + s->right.clen[cf]; |
| |
| /* Mark the contents of the first set */ |
| for (i = cf; i <= cb; ++i) { |
| s->stuff[a[i]] = 1; |
| } |
| |
| /* Add elements from second set not present in the first */ |
| for (i = cf; i <= cb; ++i) { |
| k = b[i]; |
| if (!s->stuff[k]) add_diff(s, k); |
| } |
| |
| /* Clear the marks of the first set */ |
| for (i = cf; i <= cb; ++i) { |
| s->stuff[a[i]] = 0; |
| } |
| } |
| |
| static void |
| fix_diffs(struct saucy *s, int cf, int ff) |
| { |
| int min; |
| |
| /* Check for singleton cases in both cells */ |
| fix_diff_singleton(s, cf); |
| fix_diff_singleton(s, ff); |
| |
| /* If they're both nonsingleton, do subtraction on smaller */ |
| if (s->right.clen[cf] && s->right.clen[ff]) { |
| min = s->right.clen[cf] < s->right.clen[ff] ? cf : ff; |
| fix_diff_subtract(s, min, s->left.lab, s->right.lab); |
| fix_diff_subtract(s, min, s->right.lab, s->left.lab); |
| } |
| } |
| |
| static void |
| split_color(struct coloring *c, int cf, int ff) |
| { |
| int cb, fb; |
| |
| /* Fix lengths */ |
| fb = ff - 1; |
| cb = cf + c->clen[cf]; |
| c->clen[cf] = fb - cf; |
| c->clen[ff] = cb - ff; |
| |
| /* Fix cell front pointers */ |
| fix_fronts(c, ff, ff); |
| } |
| |
| static void |
| split_common(struct saucy *s, struct coloring *c, int cf, int ff) |
| { |
| split_color(c, cf, ff); |
| |
| /* Add to refinement */ |
| if (s->indmark[cf] || c->clen[ff] < c->clen[cf]) { |
| add_induce(s, c, ff); |
| } |
| else { |
| add_induce(s, c, cf); |
| } |
| } |
| |
| static int |
| split_left(struct saucy *s, struct coloring *c, int cf, int ff) |
| { |
| /* Record the split */ |
| s->splitwho[s->nsplits] = ff; |
| s->splitfrom[s->nsplits] = cf; |
| ++s->nsplits; |
| |
| /* Do common splitting tasks */ |
| split_common(s, c, cf, ff); |
| |
| /* Always succeeds */ |
| return 1; |
| } |
| |
| static int |
| split_init(struct saucy *s, struct coloring *c, int cf, int ff) |
| { |
| split_left(s, c, cf, ff); |
| |
| /* Maintain nonsingleton list for finding new targets */ |
| if (c->clen[ff]) { |
| s->prevnon[s->nextnon[cf]] = ff; |
| s->nextnon[ff] = s->nextnon[cf]; |
| s->prevnon[ff] = cf; |
| s->nextnon[cf] = ff; |
| } |
| if (!c->clen[cf]) { |
| s->nextnon[s->prevnon[cf]] = s->nextnon[cf]; |
| s->prevnon[s->nextnon[cf]] = s->prevnon[cf]; |
| } |
| |
| /* Always succeeds */ |
| return 1; |
| } |
| |
| static int |
| split_other(struct saucy *s, struct coloring *c, int cf, int ff) |
| { |
| int k = s->nsplits; |
| |
| /* Verify the split with init */ |
| if (s->splitwho[k] != ff || s->splitfrom[k] != cf |
| || k >= s->splitlev[s->lev]) { |
| return 0; |
| } |
| ++s->nsplits; |
| |
| /* Do common splitting tasks */ |
| split_common(s, c, cf, ff); |
| |
| /* Fix differences with init */ |
| fix_diffs(s, cf, ff); |
| |
| /* If we got this far we succeeded */ |
| return 1; |
| } |
| |
| static int |
| print_partition(struct coloring *left, struct coloring *right, int n, Abc_Ntk_t * pNtk, int fNames) |
| { |
| int i, j; |
| |
| printf("top = |"); |
| for(i = 0; i < n; i += (left->clen[i]+1)) { |
| for(j = 0; j < (left->clen[i]+1); j++) { |
| if (fNames) printf("%s ", getVertexName(pNtk, left->lab[i+j])); |
| else printf("%d ", left->lab[i+j]); |
| } |
| if((i+left->clen[i]+1) < n) printf("|"); |
| } |
| printf("|\n"); |
| |
| /*printf("(cfront = {"); |
| for (i = 0; i < n; i++) |
| printf("%d ", left->cfront[i]); |
| printf("})\n");*/ |
| |
| if (right == NULL) return 1; |
| |
| printf("bot = |"); |
| for(i = 0; i < n; i += (right->clen[i]+1)) { |
| for(j = 0; j < (right->clen[i]+1); j++) { |
| if (fNames) printf("%s ", getVertexName(pNtk, right->lab[i+j])); |
| else printf("%d ", right->lab[i+j]); |
| } |
| if((i+right->clen[i]+1) < n) printf("|"); |
| } |
| printf("|\n"); |
| |
| /*printf("(cfront = {"); |
| for (i = 0; i < n; i++) |
| printf("%d ", right->cfront[i]); |
| printf("})\n");*/ |
| |
| return 1; |
| } |
| |
| static int |
| refine_cell(struct saucy *s, struct coloring *c, |
| int (*refine)(struct saucy *, struct coloring *, int)) |
| { |
| int i, cf, ret = 1; |
| |
| /* |
| * The connected list must be consistent. This is for |
| * detecting mappings across nodes at a given level. However, |
| * at the root of the tree, we never have to map with another |
| * node, so we lack this consistency constraint in that case. |
| */ |
| if (s->lev > 1) introsort(s->clist, s->csize); |
| |
| /* Now iterate over the marked cells */ |
| for (i = 0; ret && i < s->csize; ++i) { |
| cf = s->clist[i]; |
| ret = refine(s, c, cf); |
| } |
| |
| /* Clear the connected marks */ |
| for (i = 0; i < s->csize; ++i) { |
| cf = s->clist[i]; |
| s->conncnts[cf] = 0; |
| } |
| s->csize = 0; |
| return ret; |
| } |
| |
| static int |
| maybe_split(struct saucy *s, struct coloring *c, int cf, int ff) |
| { |
| return cf == ff ? 1 : s->split(s, c, cf, ff); |
| } |
| |
| static int |
| ref_single_cell(struct saucy *s, struct coloring *c, int cf) |
| { |
| int zcnt = c->clen[cf] + 1 - s->conncnts[cf]; |
| return maybe_split(s, c, cf, cf + zcnt); |
| } |
| |
| static int |
| ref_singleton(struct saucy *s, struct coloring *c, |
| const int *adj, const int *edg, int cf) |
| { |
| int i, k = c->lab[cf]; |
| |
| /* Find the cells we're connected to, and mark our neighbors */ |
| for (i = adj[k]; i != adj[k+1]; ++i) { |
| data_mark(s, c, edg[i]); |
| } |
| |
| /* Refine the cells we're connected to */ |
| return refine_cell(s, c, ref_single_cell); |
| } |
| |
| static int |
| ref_singleton_directed(struct saucy *s, struct coloring *c, int cf) |
| { |
| return ref_singleton(s, c, s->adj, s->edg, cf) |
| && ref_singleton(s, c, s->dadj, s->dedg, cf); |
| } |
| |
| static int |
| ref_singleton_undirected(struct saucy *s, struct coloring *c, int cf) |
| { |
| return ref_singleton(s, c, s->adj, s->edg, cf); |
| } |
| |
| static int |
| ref_nonsingle_cell(struct saucy *s, struct coloring *c, int cf) |
| { |
| int cnt, i, cb, nzf, ff, fb, bmin, bmax; |
| |
| /* Find the front and back */ |
| cb = cf + c->clen[cf]; |
| nzf = cb - s->conncnts[cf] + 1; |
| |
| /* Prepare the buckets */ |
| ff = nzf; |
| cnt = s->ccount[c->lab[ff]]; |
| s->count[ff] = bmin = bmax = cnt; |
| s->bucket[cnt] = 1; |
| |
| /* Iterate through the rest of the vertices */ |
| while (++ff <= cb) { |
| cnt = s->ccount[c->lab[ff]]; |
| |
| /* Initialize intermediate buckets */ |
| while (bmin > cnt) s->bucket[--bmin] = 0; |
| while (bmax < cnt) s->bucket[++bmax] = 0; |
| |
| /* Mark this count */ |
| ++s->bucket[cnt]; |
| s->count[ff] = cnt; |
| } |
| |
| /* If they all had the same count, bail */ |
| if (bmin == bmax && cf == nzf) return 1; |
| ff = fb = nzf; |
| |
| /* Calculate bucket locations, sizes */ |
| for (i = bmin; i <= bmax; ++i, ff = fb) { |
| if (!s->bucket[i]) continue; |
| fb = ff + s->bucket[i]; |
| s->bucket[i] = fb; |
| } |
| |
| /* Repair the partition nest */ |
| for (i = nzf; i <= cb; ++i) { |
| s->junk[--s->bucket[s->count[i]]] = c->lab[i]; |
| } |
| for (i = nzf; i <= cb; ++i) { |
| set_label(c, i, s->junk[i]); |
| } |
| |
| /* Split; induce */ |
| for (i = bmax; i > bmin; --i) { |
| ff = s->bucket[i]; |
| if (ff && !s->split(s, c, cf, ff)) return 0; |
| } |
| |
| /* If there was a zero area, then there's one more cell */ |
| return maybe_split(s, c, cf, s->bucket[bmin]); |
| } |
| |
| static int |
| ref_nonsingle(struct saucy *s, struct coloring *c, |
| const int *adj, const int *edg, int cf) |
| { |
| int i, j, k, ret; |
| const int cb = cf + c->clen[cf]; |
| const int size = cb - cf + 1; |
| |
| /* Double check for nonsingles which became singles later */ |
| if (cf == cb) { |
| return ref_singleton(s, c, adj, edg, cf); |
| } |
| |
| /* Establish connected list */ |
| memcpy(s->junk, c->lab + cf, size * sizeof(int)); |
| for (i = 0; i < size; ++i) { |
| k = s->junk[i]; |
| for (j = adj[k]; j != adj[k+1]; ++j) { |
| data_count(s, c, edg[j]); |
| } |
| } |
| |
| /* Refine the cells we're connected to */ |
| ret = refine_cell(s, c, ref_nonsingle_cell); |
| |
| /* Clear the counts; use lab because junk was overwritten */ |
| for (i = cf; i <= cb; ++i) { |
| k = c->lab[i]; |
| for (j = adj[k]; j != adj[k+1]; ++j) { |
| s->ccount[edg[j]] = 0; |
| } |
| } |
| |
| return ret; |
| } |
| |
| static int |
| ref_nonsingle_directed(struct saucy *s, struct coloring *c, int cf) |
| { |
| return ref_nonsingle(s, c, s->adj, s->edg, cf) |
| && ref_nonsingle(s, c, s->dadj, s->dedg, cf); |
| } |
| |
| static int |
| ref_nonsingle_undirected(struct saucy *s, struct coloring *c, int cf) |
| { |
| return ref_nonsingle(s, c, s->adj, s->edg, cf); |
| } |
| |
| static void |
| clear_refine(struct saucy *s) |
| { |
| int i; |
| for (i = 0; i < s->nninduce; ++i) { |
| s->indmark[s->ninduce[i]] = 0; |
| } |
| for (i = 0; i < s->nsinduce; ++i) { |
| s->indmark[s->sinduce[i]] = 0; |
| } |
| s->nninduce = s->nsinduce = 0; |
| } |
| |
| static int |
| refine(struct saucy *s, struct coloring *c) |
| { |
| int front; |
| |
| /* Keep going until refinement stops */ |
| while (1) { |
| |
| /* If discrete, bail */ |
| if (at_terminal(s)) { |
| clear_refine(s); |
| return 1; |
| }; |
| |
| /* Look for something else to refine on */ |
| if (s->nsinduce) { |
| front = s->sinduce[--s->nsinduce]; |
| s->indmark[front] = 0; |
| if (!s->ref_singleton(s, c, front)) break; |
| } |
| else if (s->nninduce) { |
| front = s->ninduce[--s->nninduce]; |
| s->indmark[front] = 0; |
| if (!s->ref_nonsingle(s, c, front)) break; |
| } |
| else { |
| return 1; |
| }; |
| } |
| |
| clear_refine(s); |
| return 0; |
| } |
| |
| static int |
| refineByDepGraph(struct saucy *s, struct coloring *c) |
| { |
| s->adj = s->depAdj; |
| s->edg = s->depEdg; |
| |
| return refine(s, c); |
| } |
| |
| static int |
| backtrackBysatCounterExamples(struct saucy *s, struct coloring *c) |
| { |
| int i, j, res; |
| struct sim_result * cex1, * cex2; |
| int * flag = zeros(Vec_PtrSize(s->satCounterExamples)); |
| |
| if (c == &s->left) return 1; |
| if (Vec_PtrSize(s->satCounterExamples) == 0) return 1; |
| |
| for (i = 0; i < Vec_PtrSize(s->satCounterExamples); i++) { |
| cex1 = (struct sim_result *)Vec_PtrEntry(s->satCounterExamples, i); |
| |
| for (j = 0; j < Vec_PtrSize(s->satCounterExamples); j++) { |
| if (flag[j]) continue; |
| |
| cex2 = (struct sim_result *)Vec_PtrEntry(s->satCounterExamples, j); |
| res = ifInputVectorsAreConsistent(s, cex1->inVec, cex2->inVec); |
| |
| if (res == -2) { |
| flag[j] = 1; |
| continue; |
| } |
| if (res == -1) break; |
| if (res == 0) continue; |
| |
| if (cex1->outVecOnes != cex2->outVecOnes) { |
| bumpActivity(s, cex1); |
| bumpActivity(s, cex2); |
| ABC_FREE(flag); |
| return 0; |
| } |
| |
| /* if two input vectors produce the same number of ones (look above), and |
| * pNtk's number of outputs is 1, then output vectors are definitely consistent. */ |
| if (Abc_NtkPoNum(s->pNtk) == 1) continue; |
| |
| if (!ifOutputVectorsAreConsistent(s, cex1->outVec, cex2->outVec)) { |
| bumpActivity(s, cex1); |
| bumpActivity(s, cex2); |
| ABC_FREE(flag); |
| return 0; |
| } |
| } |
| } |
| |
| ABC_FREE(flag); |
| return 1; |
| } |
| |
| static int |
| refineBySim1_init(struct saucy *s, struct coloring *c) |
| { |
| struct saucy_graph *g; |
| Vec_Int_t * randVec; |
| int i, j; |
| int allOutputsAreDistinguished; |
| int nsplits; |
| |
| if (Abc_NtkPoNum(s->pNtk) == 1) return 1; |
| |
| for (i = 0; i < NUM_SIM1_ITERATION; i++) { |
| |
| /* if all outputs are distinguished, quit */ |
| allOutputsAreDistinguished = 1; |
| for (j = 0; j < Abc_NtkPoNum(s->pNtk); j++) { |
| if (c->clen[j]) { |
| allOutputsAreDistinguished = 0; |
| break; |
| } |
| } |
| if (allOutputsAreDistinguished) break; |
| |
| randVec = assignRandomBitsToCells(s->pNtk, c); |
| g = buildSim1Graph(s->pNtk, c, randVec, s->iDep, s->oDep); |
| assert(g != NULL); |
| |
| s->adj = g->adj; |
| s->edg = g->edg; |
| |
| nsplits = s->nsplits; |
| |
| for (j = 0; j < s->n; j += c->clen[j]+1) |
| add_induce(s, c, j); |
| refine(s, c); |
| |
| if (s->nsplits > nsplits) { |
| i = 0; /* reset i */ |
| /* do more refinement by dependency graph */ |
| for (j = 0; j < s->n; j += c->clen[j]+1) |
| add_induce(s, c, j); |
| refineByDepGraph(s, c); |
| } |
| |
| Vec_IntFree(randVec); |
| ABC_FREE( g->adj ); |
| ABC_FREE( g->edg ); |
| ABC_FREE( g ); |
| } |
| |
| return 1; |
| } |
| |
| |
| static int |
| refineBySim1_left(struct saucy *s, struct coloring *c) |
| { |
| struct saucy_graph *g; |
| Vec_Int_t * randVec; |
| int i, j; |
| int allOutputsAreDistinguished; |
| int nsplits; |
| |
| if (Abc_NtkPoNum(s->pNtk) == 1) return 1; |
| |
| for (i = 0; i < NUM_SIM1_ITERATION; i++) { |
| |
| /* if all outputs are distinguished, quit */ |
| allOutputsAreDistinguished = 1; |
| for (j = 0; j < Abc_NtkPoNum(s->pNtk); j++) { |
| if (c->clen[j]) { |
| allOutputsAreDistinguished = 0; |
| break; |
| } |
| } |
| if (allOutputsAreDistinguished) break; |
| |
| randVec = assignRandomBitsToCells(s->pNtk, c); |
| g = buildSim1Graph(s->pNtk, c, randVec, s->iDep, s->oDep); |
| assert(g != NULL); |
| |
| s->adj = g->adj; |
| s->edg = g->edg; |
| |
| nsplits = s->nsplits; |
| |
| for (j = 0; j < s->n; j += c->clen[j]+1) |
| add_induce(s, c, j); |
| refine(s, c); |
| |
| if (s->nsplits > nsplits) { |
| /* save the random vector */ |
| Vec_PtrPush(s->randomVectorArray_sim1, randVec); |
| i = 0; /* reset i */ |
| /* do more refinement by dependency graph */ |
| for (j = 0; j < s->n; j += c->clen[j]+1) |
| add_induce(s, c, j); |
| refineByDepGraph(s, c); |
| } |
| else |
| Vec_IntFree(randVec); |
| |
| ABC_FREE( g->adj ); |
| ABC_FREE( g->edg ); |
| ABC_FREE( g ); |
| } |
| |
| s->randomVectorSplit_sim1[s->lev] = Vec_PtrSize(s->randomVectorArray_sim1); |
| |
| return 1; |
| } |
| |
| static int |
| refineBySim1_other(struct saucy *s, struct coloring *c) |
| { |
| struct saucy_graph *g; |
| Vec_Int_t * randVec; |
| int i, j; |
| int ret, nsplits; |
| |
| for (i = s->randomVectorSplit_sim1[s->lev-1]; i < s->randomVectorSplit_sim1[s->lev]; i++) { |
| randVec = (Vec_Int_t *)Vec_PtrEntry(s->randomVectorArray_sim1, i); |
| g = buildSim1Graph(s->pNtk, c, randVec, s->iDep, s->oDep); |
| |
| if (g == NULL) { |
| assert(c == &s->right); |
| return 0; |
| } |
| |
| s->adj = g->adj; |
| s->edg = g->edg; |
| |
| nsplits = s->nsplits; |
| |
| for (j = 0; j < s->n; j += c->clen[j]+1) |
| add_induce(s, c, j); |
| ret = refine(s, c); |
| |
| if (s->nsplits == nsplits) { |
| assert(c == &s->right); |
| ret = 0; |
| } |
| |
| if (ret) { |
| /* do more refinement now by dependency graph */ |
| for (j = 0; j < s->n; j += c->clen[j]+1) |
| add_induce(s, c, j); |
| ret = refineByDepGraph(s, c); |
| } |
| |
| ABC_FREE( g->adj ); |
| ABC_FREE( g->edg ); |
| ABC_FREE( g ); |
| |
| if (!ret) return 0; |
| } |
| |
| return 1; |
| } |
| |
| static int |
| refineBySim2_init(struct saucy *s, struct coloring *c) |
| { |
| struct saucy_graph *g; |
| Vec_Int_t * randVec; |
| int i, j; |
| int nsplits; |
| |
| for (i = 0; i < NUM_SIM2_ITERATION; i++) { |
| randVec = assignRandomBitsToCells(s->pNtk, c); |
| g = buildSim2Graph(s->pNtk, c, randVec, s->iDep, s->oDep, s->topOrder, s->obs, s->ctrl); |
| assert(g != NULL); |
| |
| s->adj = g->adj; |
| s->edg = g->edg; |
| |
| nsplits = s->nsplits; |
| |
| for (j = 0; j < s->n; j += c->clen[j]+1) |
| add_induce(s, c, j); |
| refine(s, c); |
| |
| if (s->nsplits > nsplits) { |
| i = 0; /* reset i */ |
| /* do more refinement by dependency graph */ |
| for (j = 0; j < s->n; j += c->clen[j]+1) |
| add_induce(s, c, j); |
| refineByDepGraph(s, c); |
| } |
| |
| Vec_IntFree(randVec); |
| |
| ABC_FREE( g->adj ); |
| ABC_FREE( g->edg ); |
| ABC_FREE( g ); |
| } |
| |
| return 1; |
| } |
| |
| static int |
| refineBySim2_left(struct saucy *s, struct coloring *c) |
| { |
| struct saucy_graph *g; |
| Vec_Int_t * randVec; |
| int i, j; |
| int nsplits; |
| |
| for (i = 0; i < NUM_SIM2_ITERATION; i++) { |
| randVec = assignRandomBitsToCells(s->pNtk, c); |
| g = buildSim2Graph(s->pNtk, c, randVec, s->iDep, s->oDep, s->topOrder, s->obs, s->ctrl); |
| assert(g != NULL); |
| |
| s->adj = g->adj; |
| s->edg = g->edg; |
| |
| nsplits = s->nsplits; |
| |
| for (j = 0; j < s->n; j += c->clen[j]+1) |
| add_induce(s, c, j); |
| refine(s, c); |
| |
| if (s->nsplits > nsplits) { |
| /* save the random vector */ |
| Vec_PtrPush(s->randomVectorArray_sim2, randVec); |
| i = 0; /* reset i */ |
| /* do more refinement by dependency graph */ |
| for (j = 0; j < s->n; j += c->clen[j]+1) |
| add_induce(s, c, j); |
| refineByDepGraph(s, c); |
| } |
| else |
| Vec_IntFree(randVec); |
| |
| ABC_FREE( g->adj ); |
| ABC_FREE( g->edg ); |
| ABC_FREE( g ); |
| } |
| |
| s->randomVectorSplit_sim2[s->lev] = Vec_PtrSize(s->randomVectorArray_sim2); |
| |
| return 1; |
| } |
| |
| static int |
| refineBySim2_other(struct saucy *s, struct coloring *c) |
| { |
| struct saucy_graph *g; |
| Vec_Int_t * randVec; |
| int i, j; |
| int ret, nsplits; |
| |
| for (i = s->randomVectorSplit_sim2[s->lev-1]; i < s->randomVectorSplit_sim2[s->lev]; i++) { |
| randVec = (Vec_Int_t *)Vec_PtrEntry(s->randomVectorArray_sim2, i); |
| g = buildSim2Graph(s->pNtk, c, randVec, s->iDep, s->oDep, s->topOrder, s->obs, s->ctrl); |
| |
| if (g == NULL) { |
| assert(c == &s->right); |
| return 0; |
| } |
| |
| s->adj = g->adj; |
| s->edg = g->edg; |
| |
| nsplits = s->nsplits; |
| |
| for (j = 0; j < s->n; j += c->clen[j]+1) |
| add_induce(s, c, j); |
| ret = refine(s, c); |
| |
| if (s->nsplits == nsplits) { |
| assert(c == &s->right); |
| ret = 0; |
| } |
| |
| if (ret) { |
| /* do more refinement by dependency graph */ |
| for (j = 0; j < s->n; j += c->clen[j]+1) |
| add_induce(s, c, j); |
| ret = refineByDepGraph(s, c); |
| } |
| |
| ABC_FREE( g->adj ); |
| ABC_FREE( g->edg ); |
| ABC_FREE( g ); |
| |
| if (!ret) { |
| assert(c == &s->right); |
| return 0; |
| } |
| } |
| |
| return 1; |
| } |
| |
| static int |
| check_OPP_only_has_swaps(struct saucy *s, struct coloring *c) |
| { |
| int j, cell; |
| Vec_Int_t * left_cfront, * right_cfront; |
| |
| if (c == &s->left) |
| return 1; |
| |
| left_cfront = Vec_IntAlloc (1); |
| right_cfront = Vec_IntAlloc (1); |
| |
| for (cell = 0; cell < s->n; cell += (s->left.clen[cell]+1)) { |
| for (j = cell; j <= (cell+s->left.clen[cell]); j++) { |
| Vec_IntPush(left_cfront, s->left.cfront[s->right.lab[j]]); |
| Vec_IntPush(right_cfront, s->right.cfront[s->left.lab[j]]); |
| } |
| Vec_IntSortUnsigned(left_cfront); |
| Vec_IntSortUnsigned(right_cfront); |
| for (j = 0; j < Vec_IntSize(left_cfront); j++) { |
| if (Vec_IntEntry(left_cfront, j) != Vec_IntEntry(right_cfront, j)) { |
| Vec_IntFree(left_cfront); |
| Vec_IntFree(right_cfront); |
| return 0; |
| } |
| } |
| Vec_IntClear(left_cfront); |
| Vec_IntClear(right_cfront); |
| } |
| |
| Vec_IntFree(left_cfront); |
| Vec_IntFree(right_cfront); |
| |
| return 1; |
| } |
| |
| static int |
| check_OPP_for_Boolean_matching(struct saucy *s, struct coloring *c) |
| { |
| int j, cell; |
| int countN1Left, countN2Left; |
| int countN1Right, countN2Right; |
| char *name; |
| |
| if (c == &s->left) |
| return 1; |
| |
| for (cell = 0; cell < s->n; cell += (s->right.clen[cell]+1)) { |
| countN1Left = countN2Left = countN1Right = countN2Right = 0; |
| |
| for (j = cell; j <= (cell+s->right.clen[cell]); j++) { |
| |
| name = getVertexName(s->pNtk, s->left.lab[j]); |
| assert(name[0] == 'N' && name[2] == ':'); |
| if (name[1] == '1') |
| countN1Left++; |
| else { |
| assert(name[1] == '2'); |
| countN2Left++; |
| } |
| |
| name = getVertexName(s->pNtk, s->right.lab[j]); |
| assert(name[0] == 'N' && name[2] == ':'); |
| if (name[1] == '1') |
| countN1Right++; |
| else { |
| assert(name[1] == '2'); |
| countN2Right++; |
| } |
| |
| } |
| |
| if (countN1Left != countN2Right || countN2Left != countN1Right) |
| return 0; |
| } |
| |
| return 1; |
| } |
| |
| static int |
| double_check_OPP_isomorphism(struct saucy *s, struct coloring * c) |
| { |
| /* This is the new enhancement in saucy 3.0 */ |
| int i, j, v, sum1, sum2, xor1, xor2; |
| |
| if (c == &s->left) |
| return 1; |
| |
| for (i = s->nsplits - 1; i > s->splitlev[s->lev-1]; --i) { |
| v = c->lab[s->splitwho[i]]; |
| sum1 = xor1 = 0; |
| for (j = s->adj[v]; j < s->adj[v+1]; j++) { |
| sum1 += c->cfront[s->edg[j]]; |
| xor1 ^= c->cfront[s->edg[j]]; |
| } |
| v = s->left.lab[s->splitwho[i]]; |
| sum2 = xor2 = 0; |
| for (j = s->adj[v]; j < s->adj[v+1]; j++) { |
| sum2 += s->left.cfront[s->edg[j]]; |
| xor2 ^= s->left.cfront[s->edg[j]]; |
| } |
| if ((sum1 != sum2) || (xor1 != xor2)) |
| return 0; |
| v = c->lab[s->splitfrom[i]]; |
| sum1 = xor1 = 0; |
| for (j = s->adj[v]; j < s->adj[v+1]; j++) { |
| sum1 += c->cfront[s->edg[j]]; |
| xor1 ^= c->cfront[s->edg[j]]; |
| } |
| v = s->left.lab[s->splitfrom[i]]; |
| sum2 = xor2 = 0; |
| for (j = s->adj[v]; j < s->adj[v+1]; j++) { |
| sum2 += s->left.cfront[s->edg[j]]; |
| xor2 ^= s->left.cfront[s->edg[j]]; |
| } |
| if ((sum1 != sum2) || (xor1 != xor2)) |
| return 0; |
| } |
| |
| return 1; |
| } |
| |
| static int |
| descend(struct saucy *s, struct coloring *c, int target, int min) |
| { |
| int back = target + c->clen[target]; |
| |
| /* Count this node */ |
| ++s->stats->nodes; |
| |
| /* Move the minimum label to the back */ |
| swap_labels(c, min, back); |
| |
| /* Split the cell */ |
| s->difflev[s->lev] = s->ndiffs; |
| s->undifflev[s->lev] = s->nundiffs; |
| ++s->lev; |
| s->split(s, c, target, back); |
| |
| /* Now go and do some work */ |
| //print_partition(&s->left, NULL, s->n, s->pNtk, 1); |
| if (!refineByDepGraph(s, c)) return 0; |
| |
| /* if we are looking for a Boolean matching, check the OPP and |
| * backtrack if the OPP maps part of one network to itself */ |
| if (s->fBooleanMatching && !check_OPP_for_Boolean_matching(s, c)) return 0; |
| |
| //print_partition(&s->left, NULL, s->n, s->pNtk, 1); |
| if (REFINE_BY_SIM_1 && !s->refineBySim1(s, c)) return 0; |
| |
| //print_partition(&s->left, NULL, s->n, s->pNtk, 1); |
| if (REFINE_BY_SIM_2 && !s->refineBySim2(s, c)) return 0; |
| |
| /* do the check once more, maybe the check fails, now that refinement is complete */ |
| if (s->fBooleanMatching && !check_OPP_for_Boolean_matching(s, c)) return 0; |
| |
| if (s->fLookForSwaps && !check_OPP_only_has_swaps(s, c)) return 0; |
| |
| if (!double_check_OPP_isomorphism(s, c)) return 0; |
| |
| return 1; |
| } |
| |
| static int |
| select_smallest_max_connected_cell(struct saucy *s, int start, int end) |
| { |
| int smallest_cell = -1, cell; |
| int smallest_cell_size = s->n; |
| int max_connections = -1; |
| int * connection_list = zeros(s->n); |
| |
| cell = start; |
| while( !s->left.clen[cell] ) cell++; |
| while( cell < end ) { |
| if (s->left.clen[cell] <= smallest_cell_size) { |
| int i, connections = 0;; |
| for (i = s->depAdj[s->left.lab[cell]]; i < s->depAdj[s->left.lab[cell]+1]; i++) { |
| if (!connection_list[s->depEdg[i]]) { |
| connections++; |
| connection_list[s->depEdg[i]] = 1; |
| } |
| } |
| if ((s->left.clen[cell] < smallest_cell_size) || (connections > max_connections)) { |
| smallest_cell_size = s->left.clen[cell]; |
| max_connections = connections; |
| smallest_cell = cell; |
| } |
| for (i = s->depAdj[s->left.lab[cell]]; i < s->depAdj[s->left.lab[cell]+1]; i++) |
| connection_list[s->depEdg[i]] = 0; |
| } |
| cell = s->nextnon[cell]; |
| } |
| |
| ABC_FREE( connection_list ); |
| return smallest_cell; |
| } |
| |
| static int |
| descend_leftmost(struct saucy *s) |
| { |
| int target, min; |
| |
| /* Keep going until we're discrete */ |
| //print_partition(&s->left, NULL, s->n, s->pNtk, 1); |
| while (!at_terminal(s)) { |
| //target = min = s->nextnon[-1]; |
| if (s->nextnon[-1] < Abc_NtkPoNum(s->pNtk)) |
| target = min = select_smallest_max_connected_cell(s, s->nextnon[-1], Abc_NtkPoNum(s->pNtk)); |
| else |
| target = min = select_smallest_max_connected_cell(s, Abc_NtkPoNum(s->pNtk), s->n); |
| if (s->fPrintTree) |
| printf("%s->%s\n", getVertexName(s->pNtk, s->left.lab[min]), getVertexName(s->pNtk, s->left.lab[min])); |
| s->splitvar[s->lev] = s->left.lab[min]; |
| s->start[s->lev] = target; |
| s->splitlev[s->lev] = s->nsplits; |
| if (!descend(s, &s->left, target, min)) return 0; |
| } |
| s->splitlev[s->lev] = s->n; |
| return 1; |
| } |
| |
| /* |
| * If the remaining nonsingletons in this partition match exactly |
| * those nonsingletons from the leftmost branch of the search tree, |
| * then there is no point in continuing descent. |
| */ |
| |
| static int |
| zeta_fixed(struct saucy *s) |
| { |
| return s->ndiffs == s->nundiffs; |
| } |
| |
| static void |
| select_dynamically(struct saucy *s, int *target, int *lmin, int *rmin) |
| { |
| /* Both clens are equal; this clarifies the code a bit */ |
| const int *clen = s->left.clen; |
| int i, k; |
| //int cf; |
| |
| /* |
| * If there's a pair, use it. pairs[0] should always work, |
| * but we use a checked loop instead because I'm not 100% sure |
| * I'm "unpairing" at every point I should be. |
| */ |
| for (i = 0; i < s->npairs; ++i) { |
| k = s->pairs[i]; |
| *target = s->right.cfront[k]; |
| *lmin = s->left.unlab[s->right.lab[s->left.unlab[k]]]; |
| *rmin = s->right.unlab[k]; |
| |
| if (clen[*target] |
| && in_cell_range(&s->left, *lmin, *target) |
| && in_cell_range(&s->right, *rmin, *target)) |
| return; |
| } |
| |
| /* Diffnons is only consistent when there are no baddies */ |
| /*if (s->ndiffnons != -1) { |
| *target = *lmin = *rmin = s->right.cfront[s->diffnons[0]]; |
| return; |
| }*/ |
| |
| /* Pick any old target cell and element */ |
| /*for (i = 0; i < s->ndiffs; ++i) { |
| cf = s->right.cfront[s->diffs[i]]; |
| if (clen[cf]) { |
| *lmin = *rmin = *target = cf; |
| return; |
| } |
| }*/ |
| |
| for (i = 0; i < s->n; i += (clen[i]+1)) { |
| if (!clen[i]) continue; |
| *rmin = *lmin = *target = i; |
| if (s->right.cfront[s->left.lab[*lmin]] == *target) |
| *rmin = s->right.unlab[s->left.lab[*lmin]]; |
| return; |
| } |
| |
| /* we should never get here */ |
| abort(); |
| } |
| |
| static void |
| select_statically(struct saucy *s, int *target, int *lmin, int *rmin) |
| { |
| int i; |
| |
| *target = *rmin = s->left.cfront[s->splitvar[s->lev]]; |
| *lmin = s->left.unlab[s->splitvar[s->lev]]; |
| /* try to map identically! */ |
| for (i = *rmin; i <= (*rmin + s->right.clen[*target]); i++) |
| if (s->right.lab[*rmin] == s->left.lab[*lmin]) { |
| *rmin = i; |
| break; |
| } |
| } |
| |
| static int |
| descend_left(struct saucy *s) |
| { |
| int target, lmin, rmin; |
| |
| /* Check that we ended at the right spot */ |
| if (s->nsplits != s->splitlev[s->lev]) return 0; |
| |
| /* Keep going until we're discrete */ |
| while (!at_terminal(s) /*&& !zeta_fixed(s)*/) { |
| |
| /* We can pick any old target cell and element */ |
| s->select_decomposition(s, &target, &lmin, &rmin); |
| |
| if (s->fPrintTree) { |
| //printf("in level %d: %d->%d\n", s->lev, s->left.lab[lmin], s->right.lab[rmin]); |
| printf("in level %d: %s->%s\n", s->lev, getVertexName(s->pNtk, s->left.lab[lmin]), getVertexName(s->pNtk, s->right.lab[rmin])); |
| } |
| |
| /* Check if we need to refine on the left */ |
| s->match = 0; |
| s->start[s->lev] = target; |
| s->split = split_left; |
| if (SELECT_DYNAMICALLY) { |
| s->refineBySim1 = refineBySim1_left; |
| s->refineBySim2 = refineBySim2_left; |
| } |
| descend(s, &s->left, target, lmin); |
| s->splitlev[s->lev] = s->nsplits; |
| s->split = split_other; |
| if (SELECT_DYNAMICALLY) { |
| s->refineBySim1 = refineBySim1_other; |
| s->refineBySim2 = refineBySim2_other; |
| } |
| --s->lev; |
| s->nsplits = s->splitlev[s->lev]; |
| |
| /* Now refine on the right and ensure matching */ |
| s->specmin[s->lev] = s->right.lab[rmin]; |
| if (!descend(s, &s->right, target, rmin)) return 0; |
| if (s->nsplits != s->splitlev[s->lev]) return 0; |
| } |
| return 1; |
| } |
| |
| static int |
| find_representative(int k, int *theta) |
| { |
| int rep, tmp; |
| |
| /* Find the minimum cell representative */ |
| for (rep = k; rep != theta[rep]; rep = theta[rep]); |
| |
| /* Update all intermediaries */ |
| while (theta[k] != rep) { |
| tmp = theta[k]; theta[k] = rep; k = tmp; |
| } |
| return rep; |
| } |
| |
| static void |
| update_theta(struct saucy *s) |
| { |
| int i, k, x, y, tmp; |
| |
| for (i = 0; i < s->ndiffs; ++i) { |
| k = s->unsupp[i]; |
| x = find_representative(k, s->theta); |
| y = find_representative(s->gamma[k], s->theta); |
| |
| if (x != y) { |
| if (x > y) { |
| tmp = x; |
| x = y; |
| y = tmp; |
| } |
| s->theta[y] = x; |
| s->thsize[x] += s->thsize[y]; |
| |
| s->thnext[s->thprev[y]] = s->thnext[y]; |
| s->thprev[s->thnext[y]] = s->thprev[y]; |
| s->threp[s->thfront[y]] = s->thnext[y]; |
| } |
| } |
| } |
| |
| static int |
| theta_prune(struct saucy *s) |
| { |
| int start = s->start[s->lev]; |
| int label, rep, irep; |
| |
| irep = find_representative(s->indmin, s->theta); |
| while (s->kanctar) { |
| label = s->anctar[--s->kanctar]; |
| rep = find_representative(label, s->theta); |
| if (rep == label && rep != irep) { |
| return s->right.unlab[label] - start; |
| } |
| } |
| return -1; |
| } |
| |
| static int |
| orbit_prune(struct saucy *s) |
| { |
| int i, label, fixed, min = -1; |
| int k = s->start[s->lev]; |
| int size = s->right.clen[k] + 1; |
| int *cell = s->right.lab + k; |
| |
| /* The previously fixed value */ |
| fixed = cell[size-1]; |
| |
| /* Look for the next minimum cell representative */ |
| for (i = 0; i < size-1; ++i) { |
| label = cell[i]; |
| |
| /* Skip things we've already considered */ |
| if (label <= fixed) continue; |
| |
| /* Skip things that we'll consider later */ |
| if (min != -1 && label > cell[min]) continue; |
| |
| /* New candidate minimum */ |
| min = i; |
| } |
| |
| return min; |
| } |
| |
| static void |
| note_anctar_reps(struct saucy *s) |
| { |
| int i, j, k, m, f, rep, tmp; |
| |
| /* |
| * Undo the previous level's splits along leftmost so that we |
| * join the appropriate lists of theta reps. |
| */ |
| for (i = s->splitlev[s->anc+1]-1; i >= s->splitlev[s->anc]; --i) { |
| f = s->splitfrom[i]; |
| j = s->threp[f]; |
| k = s->threp[s->splitwho[i]]; |
| |
| s->thnext[s->thprev[j]] = k; |
| s->thnext[s->thprev[k]] = j; |
| |
| tmp = s->thprev[j]; |
| s->thprev[j] = s->thprev[k]; |
| s->thprev[k] = tmp; |
| |
| for (m = k; m != j; m = s->thnext[m]) { |
| s->thfront[m] = f; |
| } |
| } |
| |
| /* |
| * Just copy over the target's reps and sort by cell size, in |
| * the hopes of trimming some otherwise redundant generators. |
| */ |
| s->kanctar = 0; |
| s->anctar[s->kanctar++] = rep = s->threp[s->start[s->lev]]; |
| for (k = s->thnext[rep]; k != rep; k = s->thnext[k]) { |
| s->anctar[s->kanctar++] = k; |
| } |
| array_indirect_sort(s->anctar, s->thsize, s->kanctar); |
| } |
| |
| static void |
| multiply_index(struct saucy *s, int k) |
| { |
| if ((s->stats->grpsize_base *= k) > 1e10) { |
| s->stats->grpsize_base /= 1e10; |
| s->stats->grpsize_exp += 10; |
| } |
| } |
| |
| static int |
| backtrack_leftmost(struct saucy *s) |
| { |
| int rep = find_representative(s->indmin, s->theta); |
| int repsize = s->thsize[rep]; |
| int min = -1; |
| |
| pick_all_the_pairs(s); |
| clear_undiffnons(s); |
| s->ndiffs = s->nundiffs = s->npairs = s->ndiffnons = 0; |
| |
| if (repsize != s->right.clen[s->start[s->lev]]+1) { |
| min = theta_prune(s); |
| } |
| |
| if (min == -1) { |
| multiply_index(s, repsize); |
| } |
| |
| return min; |
| } |
| |
| static int |
| backtrack_other(struct saucy *s) |
| { |
| int cf = s->start[s->lev]; |
| int cb = cf + s->right.clen[cf]; |
| int spec = s->specmin[s->lev]; |
| int min; |
| |
| /* Avoid using pairs until we get back to leftmost. */ |
| pick_all_the_pairs(s); |
| |
| clear_undiffnons(s); |
| |
| s->npairs = s->ndiffnons = -1; |
| |
| if (s->right.lab[cb] == spec) { |
| min = find_min(s, cf); |
| if (min == cb) { |
| min = orbit_prune(s); |
| } |
| else { |
| min -= cf; |
| } |
| } |
| else { |
| min = orbit_prune(s); |
| if (min != -1 && s->right.lab[min + cf] == spec) { |
| swap_labels(&s->right, min + cf, cb); |
| min = orbit_prune(s); |
| } |
| } |
| return min; |
| } |
| |
| static void |
| rewind_coloring(struct saucy *s, struct coloring *c, int lev) |
| { |
| int i, cf, ff, splits = s->splitlev[lev]; |
| for (i = s->nsplits - 1; i >= splits; --i) { |
| cf = s->splitfrom[i]; |
| ff = s->splitwho[i]; |
| c->clen[cf] += c->clen[ff] + 1; |
| fix_fronts(c, cf, ff); |
| } |
| } |
| |
| static void |
| rewind_simulation_vectors(struct saucy *s, int lev) |
| { |
| int i; |
| for (i = s->randomVectorSplit_sim1[lev]; i < Vec_PtrSize(s->randomVectorArray_sim1); i++) |
| Vec_IntFree((Vec_Int_t *)Vec_PtrEntry(s->randomVectorArray_sim1, i)); |
| Vec_PtrShrink(s->randomVectorArray_sim1, s->randomVectorSplit_sim1[lev]); |
| |
| for (i = s->randomVectorSplit_sim2[lev]; i < Vec_PtrSize(s->randomVectorArray_sim2); i++) |
| Vec_IntFree((Vec_Int_t *)Vec_PtrEntry(s->randomVectorArray_sim2, i)); |
| Vec_PtrShrink(s->randomVectorArray_sim2, s->randomVectorSplit_sim2[lev]); |
| } |
| |
| static int |
| do_backtrack(struct saucy *s) |
| { |
| int i, cf, cb; |
| |
| /* Undo the splits up to this level */ |
| rewind_coloring(s, &s->right, s->lev); |
| s->nsplits = s->splitlev[s->lev]; |
| |
| /* Rewind diff information */ |
| for (i = s->ndiffs - 1; i >= s->difflev[s->lev]; --i) { |
| s->diffmark[s->diffs[i]] = 0; |
| } |
| s->ndiffs = s->difflev[s->lev]; |
| s->nundiffs = s->undifflev[s->lev]; |
| |
| /* Point to the target cell */ |
| cf = s->start[s->lev]; |
| cb = cf + s->right.clen[cf]; |
| |
| /* Update ancestor with zeta if we've rewound more */ |
| if (s->anc > s->lev) { |
| s->anc = s->lev; |
| s->indmin = s->left.lab[cb]; |
| s->match = 1; |
| note_anctar_reps(s); |
| } |
| |
| /* Perform backtracking appropriate to our location */ |
| return s->lev == s->anc |
| ? backtrack_leftmost(s) |
| : backtrack_other(s); |
| } |
| |
| static int |
| backtrack_loop(struct saucy *s) |
| { |
| int min; |
| |
| /* Backtrack as long as we're exhausting target cells */ |
| for (--s->lev; s->lev; --s->lev) { |
| min = do_backtrack(s); |
| if (min != -1) return min + s->start[s->lev]; |
| } |
| return -1; |
| } |
| |
| static int |
| backtrack(struct saucy *s) |
| { |
| int min, old, tmp; |
| old = s->nsplits; |
| min = backtrack_loop(s); |
| tmp = s->nsplits; |
| s->nsplits = old; |
| rewind_coloring(s, &s->left, s->lev+1); |
| s->nsplits = tmp; |
| if (SELECT_DYNAMICALLY) |
| rewind_simulation_vectors(s, s->lev+1); |
| |
| return min; |
| } |
| |
| static int |
| backtrack_bad(struct saucy *s) |
| { |
| int min, old, tmp; |
| old = s->lev; |
| min = backtrack_loop(s); |
| if (BACKTRACK_BY_SAT) { |
| int oldLev = s->lev; |
| while (!backtrackBysatCounterExamples(s, &s->right)) { |
| min = backtrack_loop(s); |
| if (!s->lev) { |
| if (s->fPrintTree) |
| printf("Backtrack by SAT from level %d to %d\n", oldLev, 0); |
| return -1; |
| } |
| } |
| if (s->fPrintTree) |
| if (s->lev < oldLev) |
| printf("Backtrack by SAT from level %d to %d\n", oldLev, s->lev); |
| } |
| tmp = s->nsplits; |
| s->nsplits = s->splitlev[old]; |
| rewind_coloring(s, &s->left, s->lev+1); |
| s->nsplits = tmp; |
| if (SELECT_DYNAMICALLY) |
| rewind_simulation_vectors(s, s->lev+1); |
| |
| return min; |
| } |
| |
| void |
| prepare_permutation_ntk(struct saucy *s) |
| { |
| int i; |
| Abc_Obj_t * pObj, * pObjPerm; |
| int numouts = Abc_NtkPoNum(s->pNtk); |
| |
| Nm_ManFree( s->pNtk_permuted->pManName ); |
| s->pNtk_permuted->pManName = Nm_ManCreate( Abc_NtkCiNum(s->pNtk) + Abc_NtkCoNum(s->pNtk) + Abc_NtkBoxNum(s->pNtk) ); |
| |
| for (i = 0; i < s->n; ++i) { |
| if (i < numouts) { |
| pObj = (Abc_Obj_t *)Vec_PtrEntry(s->pNtk->vPos, i); |
| pObjPerm = (Abc_Obj_t *)Vec_PtrEntry(s->pNtk_permuted->vPos, s->gamma[i]); |
| } |
| else { |
| pObj = (Abc_Obj_t *)Vec_PtrEntry(s->pNtk->vPis, i - numouts); |
| pObjPerm = (Abc_Obj_t *)Vec_PtrEntry(s->pNtk_permuted->vPis, s->gamma[i] - numouts); |
| |
| } |
| Abc_ObjAssignName( pObjPerm, Abc_ObjName(pObj), NULL ); |
| } |
| |
| Abc_NtkOrderObjsByName( s->pNtk_permuted, 1 ); |
| |
| /* print the permutation */ |
| /*for (i = 0; i < s->ndiffs; ++i) |
| printf(" %d->%d", s->unsupp[i], s->diffs[i]); |
| printf("\n"); |
| Abc_NtkForEachCo( s->pNtk, pObj, i ) |
| printf (" %d", Abc_ObjId(pObj)-1-Abc_NtkPiNum(s->pNtk)); |
| Abc_NtkForEachCi( s->pNtk, pObj, i ) |
| printf (" %d", Abc_ObjId(pObj)-1+Abc_NtkPoNum(s->pNtk)); |
| printf("\n"); |
| Abc_NtkForEachCo( s->pNtk_permuted, pObj, i ) |
| printf (" %d", Abc_ObjId(pObj)-1-Abc_NtkPiNum(s->pNtk_permuted)); |
| Abc_NtkForEachCi( s->pNtk_permuted, pObj, i ) |
| printf (" %d", Abc_ObjId(pObj)-1+Abc_NtkPoNum(s->pNtk_permuted)); |
| printf("\n");*/ |
| } |
| |
| |
| static void |
| prepare_permutation(struct saucy *s) |
| { |
| int i, k; |
| for (i = 0; i < s->ndiffs; ++i) { |
| k = s->right.unlab[s->diffs[i]]; |
| s->unsupp[i] = s->left.lab[k]; |
| s->gamma[s->left.lab[k]] = s->right.lab[k]; |
| } |
| prepare_permutation_ntk(s); |
| } |
| |
| void |
| unprepare_permutation_ntk(struct saucy *s) |
| { |
| int i; |
| Abc_Obj_t * pObj, * pObjPerm; |
| int numouts = Abc_NtkPoNum(s->pNtk); |
| |
| Nm_ManFree( s->pNtk_permuted->pManName ); |
| s->pNtk_permuted->pManName = Nm_ManCreate( Abc_NtkCiNum(s->pNtk) + Abc_NtkCoNum(s->pNtk) + Abc_NtkBoxNum(s->pNtk) ); |
| |
| for (i = 0; i < s->n; ++i) { |
| if (i < numouts) { |
| pObj = (Abc_Obj_t *)Vec_PtrEntry(s->pNtk->vPos, s->gamma[i]); |
| pObjPerm = (Abc_Obj_t *)Vec_PtrEntry(s->pNtk_permuted->vPos, i); |
| } |
| else { |
| pObj = (Abc_Obj_t *)Vec_PtrEntry(s->pNtk->vPis, s->gamma[i] - numouts); |
| pObjPerm = (Abc_Obj_t *)Vec_PtrEntry(s->pNtk_permuted->vPis, i - numouts); |
| |
| } |
| Abc_ObjAssignName( pObjPerm, Abc_ObjName(pObj), NULL ); |
| } |
| |
| Abc_NtkOrderObjsByName( s->pNtk_permuted, 1 ); |
| } |
| |
| |
| static void |
| unprepare_permutation(struct saucy *s) |
| { |
| int i; |
| unprepare_permutation_ntk(s); |
| for (i = 0; i < s->ndiffs; ++i) { |
| s->gamma[s->unsupp[i]] = s->unsupp[i]; |
| } |
| } |
| |
| static int |
| do_search(struct saucy *s) |
| { |
| int min; |
| |
| unprepare_permutation(s); |
| |
| /* Backtrack to the ancestor with zeta */ |
| if (s->lev > s->anc) s->lev = s->anc + 1; |
| |
| /* Perform additional backtracking */ |
| min = backtrack(s); |
| |
| if (s->fBooleanMatching && (s->stats->grpsize_base > 1 || s->stats->grpsize_exp > 0)) |
| return 0; |
| |
| if (s->fPrintTree && s->lev > 0) { |
| //printf("in level %d: %d->%d\n", s->lev, s->left.lab[s->splitwho[s->nsplits]], s->right.lab[min]); |
| printf("in level %d: %s->%s\n", s->lev, getVertexName(s->pNtk, s->left.lab[s->splitwho[s->nsplits]]), getVertexName(s->pNtk, s->right.lab[min])); |
| } |
| |
| /* Keep going while there are tree nodes to expand */ |
| while (s->lev) { |
| |
| /* Descend to a new leaf node */ |
| if (descend(s, &s->right, s->start[s->lev], min) |
| && descend_left(s)) { |
| |
| /* Prepare permutation */ |
| prepare_permutation(s); |
| |
| /* If we found an automorphism, return it */ |
| if (s->is_automorphism(s)) { |
| ++s->stats->gens; |
| s->stats->support += s->ndiffs; |
| update_theta(s); |
| s->print_automorphism(s->gFile, s->n, s->gamma, s->ndiffs, s->unsupp, s->marks, s->pNtk); |
| unprepare_permutation(s); |
| return 1; |
| } |
| else { |
| unprepare_permutation(s); |
| } |
| } |
| |
| /* If we get here, something went wrong; backtrack */ |
| ++s->stats->bads; |
| min = backtrack_bad(s); |
| if (s->fPrintTree) { |
| printf("BAD NODE\n"); |
| if (s->lev > 0) { |
| //printf("in level %d: %d->%d\n", s->lev, s->left.lab[s->splitwho[s->nsplits]], s->right.lab[min]); |
| printf("in level %d: %s->%s\n", s->lev, getVertexName(s->pNtk, s->left.lab[s->splitwho[s->nsplits]]), getVertexName(s->pNtk, s->right.lab[min])); |
| } |
| } |
| } |
| |
| /* Normalize group size */ |
| while (s->stats->grpsize_base >= 10.0) { |
| s->stats->grpsize_base /= 10; |
| ++s->stats->grpsize_exp; |
| } |
| return 0; |
| } |
| |
| void |
| saucy_search( |
| Abc_Ntk_t * pNtk, |
| struct saucy *s, |
| int directed, |
| const int *colors, |
| struct saucy_stats *stats) |
| { |
| int i, j, max = 0; |
| struct saucy_graph *g; |
| |
| extern Abc_Ntk_t * Abc_NtkDup( Abc_Ntk_t * pNtk ); |
| |
| /* Save network information */ |
| s->pNtk = pNtk; |
| s->pNtk_permuted = Abc_NtkDup( pNtk ); |
| |
| /* Builde dependency graph */ |
| g = buildDepGraph(pNtk, s->iDep, s->oDep); |
| |
| /* Save graph information */ |
| s->n = g->n; |
| s->depAdj = g->adj; |
| s->depEdg = g->edg; |
| /*s->dadj = g->adj + g->n + 1; |
| s->dedg = g->edg + g->e;*/ |
| |
| /* Save client information */ |
| s->stats = stats; |
| |
| /* Polymorphism */ |
| if (directed) { |
| s->is_automorphism = is_directed_automorphism; |
| s->ref_singleton = ref_singleton_directed; |
| s->ref_nonsingle = ref_nonsingle_directed; |
| } |
| else { |
| s->is_automorphism = is_undirected_automorphism; |
| s->ref_singleton = ref_singleton_undirected; |
| s->ref_nonsingle = ref_nonsingle_undirected; |
| } |
| |
| /* Initialize scalars */ |
| s->indmin = 0; |
| s->lev = s->anc = 1; |
| s->ndiffs = s->nundiffs = s->ndiffnons = 0; |
| s->activityInc = 1; |
| |
| /* The initial orbit partition is discrete */ |
| for (i = 0; i < s->n; ++i) { |
| s->theta[i] = i; |
| } |
| |
| /* The initial permutation is the identity */ |
| for (i = 0; i < s->n; ++i) { |
| s->gamma[i] = i; |
| } |
| |
| /* Initially every cell of theta has one element */ |
| for (i = 0; i < s->n; ++i) { |
| s->thsize[i] = 1; |
| } |
| |
| /* Every theta rep list is singleton */ |
| for (i = 0; i < s->n; ++i) { |
| s->thprev[i] = s->thnext[i] = i; |
| } |
| |
| /* We have no pairs yet */ |
| s->npairs = 0; |
| for (i = 0; i < s->n; ++i) { |
| s->unpairs[i] = -1; |
| } |
| |
| /* Ensure no stray pointers in undiffnons, which is checked by removed_diffnon() */ |
| for (i = 0; i < s->n; ++i) { |
| s->undiffnons[i] = -1; |
| } |
| |
| /* Initialize stats */ |
| s->stats->grpsize_base = 1.0; |
| s->stats->grpsize_exp = 0; |
| s->stats->nodes = 1; |
| s->stats->bads = s->stats->gens = s->stats->support = 0; |
| |
| /* Prepare for refinement */ |
| s->nninduce = s->nsinduce = 0; |
| s->csize = 0; |
| |
| /* Count cell sizes */ |
| for (i = 0; i < s->n; ++i) { |
| s->ccount[colors[i]]++; |
| if (max < colors[i]) max = colors[i]; |
| } |
| s->nsplits = max + 1; |
| |
| /* Build cell lengths */ |
| s->left.clen[0] = s->ccount[0] - 1; |
| for (i = 0; i < max; ++i) { |
| s->left.clen[s->ccount[i]] = s->ccount[i+1] - 1; |
| s->ccount[i+1] += s->ccount[i]; |
| } |
| |
| /* Build the label array */ |
| for (i = 0; i < s->n; ++i) { |
| set_label(&s->left, --s->ccount[colors[i]], i); |
| } |
| |
| /* Clear out ccount */ |
| for (i = 0; i <= max; ++i) { |
| s->ccount[i] = 0; |
| } |
| |
| /* Update refinement stuff based on initial partition */ |
| for (i = 0; i < s->n; i += s->left.clen[i]+1) { |
| add_induce(s, &s->left, i); |
| fix_fronts(&s->left, i, i); |
| } |
| |
| /* Prepare lists based on cell lengths */ |
| for (i = 0, j = -1; i < s->n; i += s->left.clen[i] + 1) { |
| if (!s->left.clen[i]) continue; |
| s->prevnon[i] = j; |
| s->nextnon[j] = i; |
| j = i; |
| } |
| |
| /* Fix the end */ |
| s->prevnon[s->n] = j; |
| s->nextnon[j] = s->n; |
| |
| /* Preprocessing after initial coloring */ |
| s->split = split_init; |
| s->refineBySim1 = refineBySim1_init; |
| s->refineBySim2 = refineBySim2_init; |
| |
| //print_partition(&s->left, NULL, s->n, s->pNtk, 1); |
| printf("Initial Refine by Dependency graph ... "); |
| refineByDepGraph(s, &s->left); |
| //print_partition(&s->left, NULL, s->n, s->pNtk, 1); |
| printf("done!\n"); |
| |
| printf("Initial Refine by Simulation ... "); |
| if (REFINE_BY_SIM_1) s->refineBySim1(s, &s->left); |
| //print_partition(&s->left, NULL, s->n, s->pNtk, 1); |
| if (REFINE_BY_SIM_2) s->refineBySim2(s, &s->left); |
| //print_partition(&s->left, NULL, s->n, s->pNtk, 1); |
| printf("done!\n\t--------------------\n"); |
| |
| /* Descend along the leftmost branch and compute zeta */ |
| s->refineBySim1 = refineBySim1_left; |
| s->refineBySim2 = refineBySim2_left; |
| descend_leftmost(s); |
| s->split = split_other; |
| s->refineBySim1 = refineBySim1_other; |
| s->refineBySim2 = refineBySim2_other; |
| |
| /* Our common ancestor with zeta is the current level */ |
| s->stats->levels = s->anc = s->lev; |
| |
| /* Copy over this data to our non-leftmost coloring */ |
| memcpy(s->right.lab, s->left.lab, s->n * sizeof(int)); |
| memcpy(s->right.unlab, s->left.unlab, s->n * sizeof(int)); |
| memcpy(s->right.clen, s->left.clen, s->n * sizeof(int)); |
| memcpy(s->right.cfront, s->left.cfront, s->n * sizeof(int)); |
| |
| /* The reps are just the labels at this point */ |
| memcpy(s->threp, s->left.lab, s->n * sizeof(int)); |
| memcpy(s->thfront, s->left.unlab, s->n * sizeof(int)); |
| |
| /* choose cell selection method */ |
| if (SELECT_DYNAMICALLY) s->select_decomposition = select_dynamically; |
| else s->select_decomposition = select_statically; |
| |
| /* Keep running till we're out of automorphisms */ |
| while (do_search(s)); |
| } |
| |
| void |
| saucy_free(struct saucy *s) |
| { |
| int i; |
| |
| ABC_FREE(s->undiffnons); |
| ABC_FREE(s->diffnons); |
| ABC_FREE(s->unpairs); |
| ABC_FREE(s->pairs); |
| ABC_FREE(s->thfront); |
| ABC_FREE(s->threp); |
| ABC_FREE(s->thnext); |
| ABC_FREE(s->thprev); |
| ABC_FREE(s->specmin); |
| ABC_FREE(s->anctar); |
| ABC_FREE(s->thsize); |
| ABC_FREE(s->undifflev); |
| ABC_FREE(s->difflev); |
| ABC_FREE(s->diffs); |
| ABC_FREE(s->diffmark); |
| ABC_FREE(s->conncnts); |
| ABC_FREE(s->unsupp); |
| ABC_FREE(s->splitlev); |
| ABC_FREE(s->splitfrom); |
| ABC_FREE(s->splitwho); |
| ABC_FREE(s->splitvar); |
| ABC_FREE(s->right.unlab); |
| ABC_FREE(s->right.lab); |
| ABC_FREE(s->left.unlab); |
| ABC_FREE(s->left.lab); |
| ABC_FREE(s->theta); |
| ABC_FREE(s->junk); |
| ABC_FREE(s->gamma); |
| ABC_FREE(s->start); |
| ABC_FREE(s->prevnon); |
| free(s->nextnon-1); |
| ABC_FREE(s->clist); |
| ABC_FREE(s->ccount); |
| ABC_FREE(s->count); |
| ABC_FREE(s->bucket); |
| ABC_FREE(s->stuff); |
| ABC_FREE(s->right.clen); |
| ABC_FREE(s->right.cfront); |
| ABC_FREE(s->left.clen); |
| ABC_FREE(s->left.cfront); |
| ABC_FREE(s->indmark); |
| ABC_FREE(s->sinduce); |
| ABC_FREE(s->ninduce); |
| ABC_FREE(s->depAdj); |
| ABC_FREE(s->depEdg); |
| ABC_FREE(s->marks); |
| for (i = 0; i < Abc_NtkPiNum(s->pNtk); i++) { |
| Vec_IntFree( s->iDep[i] ); |
| Vec_IntFree( s->obs[i] ); |
| Vec_PtrFree( s->topOrder[i] ); |
| } |
| for (i = 0; i < Abc_NtkPoNum(s->pNtk); i++) { |
| Vec_IntFree( s->oDep[i] ); |
| Vec_IntFree( s->ctrl[i] ); |
| } |
| for (i = 0; i < Vec_PtrSize(s->randomVectorArray_sim1); i++) |
| Vec_IntFree((Vec_Int_t *)Vec_PtrEntry(s->randomVectorArray_sim1, i)); |
| for (i = 0; i < Vec_PtrSize(s->randomVectorArray_sim2); i++) |
| Vec_IntFree((Vec_Int_t *)Vec_PtrEntry(s->randomVectorArray_sim2, i)); |
| Vec_PtrFree( s->randomVectorArray_sim1 ); |
| Vec_PtrFree( s->randomVectorArray_sim2 ); |
| ABC_FREE(s->randomVectorSplit_sim1); |
| ABC_FREE(s->randomVectorSplit_sim2); |
| Abc_NtkDelete( s->pNtk_permuted ); |
| for (i = 0; i < Vec_PtrSize(s->satCounterExamples); i++) { |
| struct sim_result * cex = (struct sim_result *)Vec_PtrEntry(s->satCounterExamples, i); |
| ABC_FREE( cex->inVec ); |
| ABC_FREE( cex->outVec ); |
| ABC_FREE( cex ); |
| } |
| Vec_PtrFree(s->satCounterExamples); |
| ABC_FREE( s->pModel ); |
| ABC_FREE( s->iDep ); |
| ABC_FREE( s->oDep ); |
| ABC_FREE( s->obs ); |
| ABC_FREE( s->ctrl ); |
| ABC_FREE( s->topOrder ); |
| ABC_FREE(s); |
| } |
| |
| struct saucy * |
| saucy_alloc(Abc_Ntk_t * pNtk) |
| { |
| int i; |
| int numouts = Abc_NtkPoNum(pNtk); |
| int numins = Abc_NtkPiNum(pNtk); |
| int n = numins + numouts; |
| struct saucy *s = ABC_ALLOC(struct saucy, 1); |
| if (s == NULL) return NULL; |
| |
| s->ninduce = ints(n); |
| s->sinduce = ints(n); |
| s->indmark = bits(n); |
| s->left.cfront = zeros(n); |
| s->left.clen = ints(n); |
| s->right.cfront = zeros(n); |
| s->right.clen = ints(n); |
| s->stuff = bits(n+1); |
| s->bucket = ints(n+2); |
| s->count = ints(n+1); |
| s->ccount = zeros(n); |
| s->clist = ints(n); |
| s->nextnon = ints(n+1) + 1; |
| s->prevnon = ints(n+1); |
| s->anctar = ints(n); |
| s->start = ints(n); |
| s->gamma = ints(n); |
| s->junk = ints(n); |
| s->theta = ints(n); |
| s->thsize = ints(n); |
| s->left.lab = ints(n); |
| s->left.unlab = ints(n); |
| s->right.lab = ints(n); |
| s->right.unlab = ints(n); |
| s->splitvar = ints(n); |
| s->splitwho = ints(n); |
| s->splitfrom = ints(n); |
| s->splitlev = ints(n+1); |
| s->unsupp = ints(n); |
| s->conncnts = zeros(n); |
| s->diffmark = bits(n); |
| s->diffs = ints(n); |
| s->difflev = ints(n); |
| s->undifflev = ints(n); |
| s->specmin = ints(n); |
| s->thnext = ints(n); |
| s->thprev = ints(n); |
| s->threp = ints(n); |
| s->thfront = ints(n); |
| s->pairs = ints(n); |
| s->unpairs = ints(n); |
| s->diffnons = ints(n); |
| s->undiffnons = ints(n); |
| s->marks = bits(n); |
| |
| s->iDep = ABC_ALLOC( Vec_Int_t*, numins ); |
| s->oDep = ABC_ALLOC( Vec_Int_t*, numouts ); |
| s->obs = ABC_ALLOC( Vec_Int_t*, numins ); |
| s->ctrl = ABC_ALLOC( Vec_Int_t*, numouts ); |
| |
| for(i = 0; i < numins; i++) { |
| s->iDep[i] = Vec_IntAlloc( 1 ); |
| s->obs[i] = Vec_IntAlloc( 1 ); |
| } |
| for(i = 0; i < numouts; i++) { |
| s->oDep[i] = Vec_IntAlloc( 1 ); |
| s->ctrl[i] = Vec_IntAlloc( 1 ); |
| } |
| |
| s->randomVectorArray_sim1 = Vec_PtrAlloc( n ); |
| s->randomVectorSplit_sim1 = zeros( n ); |
| s->randomVectorArray_sim2 = Vec_PtrAlloc( n ); |
| s->randomVectorSplit_sim2= zeros( n ); |
| |
| s->satCounterExamples = Vec_PtrAlloc( 1 ); |
| s->pModel = ints( numins ); |
| |
| if (s->ninduce && s->sinduce && s->left.cfront && s->left.clen |
| && s->right.cfront && s->right.clen |
| && s->stuff && s->bucket && s->count && s->ccount |
| && s->clist && s->nextnon-1 && s->prevnon |
| && s->start && s->gamma && s->theta && s->left.unlab |
| && s->right.lab && s->right.unlab |
| && s->left.lab && s->splitvar && s->splitwho && s->junk |
| && s->splitfrom && s->splitlev && s->thsize |
| && s->unsupp && s->conncnts && s->anctar |
| && s->diffmark && s->diffs && s->indmark |
| && s->thnext && s->thprev && s->threp && s->thfront |
| && s->pairs && s->unpairs && s->diffnons && s->undiffnons |
| && s->difflev && s->undifflev && s->specmin) |
| { |
| return s; |
| } |
| else { |
| saucy_free(s); |
| return NULL; |
| } |
| } |
| |
| static void |
| print_stats(FILE *f, struct saucy_stats stats ) |
| { |
| fprintf(f, "group size = %fe%d\n", |
| stats.grpsize_base, stats.grpsize_exp); |
| fprintf(f, "levels = %d\n", stats.levels); |
| fprintf(f, "nodes = %d\n", stats.nodes); |
| fprintf(f, "generators = %d\n", stats.gens); |
| fprintf(f, "total support = %d\n", stats.support); |
| fprintf(f, "average support = %.2f\n",(double)(stats.support)/(double)(stats.gens)); |
| fprintf(f, "nodes per generator = %.2f\n",(double)(stats.nodes)/(double)(stats.gens)); |
| fprintf(f, "bad nodes = %d\n", stats.bads); |
| } |
| |
| |
| /* From this point up are SAUCY functions*/ |
| ///////////////////////////////////////////////////////////////////////////////////////////////////////// |
| /* From this point down are new functions */ |
| |
| static char * |
| getVertexName(Abc_Ntk_t *pNtk, int v) |
| { |
| Abc_Obj_t * pObj; |
| int numouts = Abc_NtkPoNum(pNtk); |
| |
| if (v < numouts) |
| pObj = (Abc_Obj_t *)Vec_PtrEntry(pNtk->vPos, v); |
| else |
| pObj = (Abc_Obj_t *)Vec_PtrEntry(pNtk->vPis, v - numouts); |
| |
| return Abc_ObjName(pObj); |
| } |
| |
| static Vec_Ptr_t ** |
| findTopologicalOrder( Abc_Ntk_t * pNtk ) |
| { |
| Vec_Ptr_t ** vNodes; |
| Abc_Obj_t * pObj, * pFanout; |
| int i, k; |
| |
| extern void Abc_NtkDfsReverse_rec( Abc_Obj_t * pNode, Vec_Ptr_t * vNodes ); |
| |
| /* start the array of nodes */ |
| vNodes = ABC_ALLOC(Vec_Ptr_t *, Abc_NtkPiNum(pNtk)); |
| for(i = 0; i < Abc_NtkPiNum(pNtk); i++) |
| vNodes[i] = Vec_PtrAlloc(50); |
| |
| Abc_NtkForEachCi( pNtk, pObj, i ) |
| { |
| /* set the traversal ID */ |
| Abc_NtkIncrementTravId( pNtk ); |
| Abc_NodeSetTravIdCurrent( pObj ); |
| pObj = Abc_ObjFanout0Ntk(pObj); |
| Abc_ObjForEachFanout( pObj, pFanout, k ) |
| Abc_NtkDfsReverse_rec( pFanout, vNodes[i] ); |
| } |
| |
| return vNodes; |
| } |
| |
| static void |
| getDependencies(Abc_Ntk_t *pNtk, Vec_Int_t** iDep, Vec_Int_t** oDep) |
| { |
| Vec_Ptr_t * vSuppFun; |
| int i, j; |
| |
| vSuppFun = Sim_ComputeFunSupp(pNtk, 0); |
| for(i = 0; i < Abc_NtkPoNum(pNtk); i++) { |
| char * seg = (char *)vSuppFun->pArray[i]; |
| |
| for(j = 0; j < Abc_NtkPiNum(pNtk); j+=8) { |
| if(((*seg) & 0x01) == 0x01) |
| Vec_IntPushOrder(oDep[i], j); |
| if(((*seg) & 0x02) == 0x02) |
| Vec_IntPushOrder(oDep[i], j+1); |
| if(((*seg) & 0x04) == 0x04) |
| Vec_IntPushOrder(oDep[i], j+2); |
| if(((*seg) & 0x08) == 0x08) |
| Vec_IntPushOrder(oDep[i], j+3); |
| if(((*seg) & 0x10) == 0x10) |
| Vec_IntPushOrder(oDep[i], j+4); |
| if(((*seg) & 0x20) == 0x20) |
| Vec_IntPushOrder(oDep[i], j+5); |
| if(((*seg) & 0x40) == 0x40) |
| Vec_IntPushOrder(oDep[i], j+6); |
| if(((*seg) & 0x80) == 0x80) |
| Vec_IntPushOrder(oDep[i], j+7); |
| |
| seg++; |
| } |
| } |
| |
| for(i = 0; i < Abc_NtkPoNum(pNtk); i++) |
| for(j = 0; j < Vec_IntSize(oDep[i]); j++) |
| Vec_IntPush(iDep[Vec_IntEntry(oDep[i], j)], i); |
| |
| |
| /*for(i = 0; i < Abc_NtkPoNum(pNtk); i++) |
| { |
| printf("Output %d: ", i); |
| for(j = 0; j < Vec_IntSize(oDep[i]); j++) |
| printf("%d ", Vec_IntEntry(oDep[i], j)); |
| printf("\n"); |
| } |
| |
| printf("\n"); |
| |
| for(i = 0; i < Abc_NtkPiNum(pNtk); i++) |
| { |
| printf("Input %d: ", i); |
| for(j = 0; j < Vec_IntSize(iDep[i]); j++) |
| printf("%d ", Vec_IntEntry(iDep[i], j)); |
| printf("\n"); |
| } |
| |
| printf("\n"); */ |
| } |
| |
| static void |
| getDependenciesDummy(Abc_Ntk_t *pNtk, Vec_Int_t** iDep, Vec_Int_t** oDep) |
| { |
| int i, j; |
| |
| /* let's assume that every output is dependent on every input */ |
| for(i = 0; i < Abc_NtkPoNum(pNtk); i++) |
| for(j = 0; j < Abc_NtkPiNum(pNtk); j++) |
| Vec_IntPush(oDep[i], j); |
| |
| for(i = 0; i < Abc_NtkPiNum(pNtk); i++) |
| for(j = 0; j < Abc_NtkPoNum(pNtk); j++) |
| Vec_IntPush(iDep[i], j); |
| } |
| |
| static struct saucy_graph * |
| buildDepGraph(Abc_Ntk_t *pNtk, Vec_Int_t ** iDep, Vec_Int_t ** oDep) |
| { |
| int i, j, k; |
| struct saucy_graph *g = NULL; |
| int n, e, *adj, *edg; |
| |
| n = Abc_NtkPoNum(pNtk) + Abc_NtkPiNum(pNtk); |
| for (e = 0, i = 0; i < Abc_NtkPoNum(pNtk); i++) |
| e += Vec_IntSize(oDep[i]); |
| |
| g = ABC_ALLOC(struct saucy_graph, 1); |
| adj = zeros(n+1); |
| edg = ints(2*e); |
| |
| g->n = n; |
| g->e = e; |
| g->adj = adj; |
| g->edg = edg; |
| |
| adj[0] = 0; |
| for (i = 0; i < n; i++) { |
| /* first add outputs and then inputs */ |
| if ( i < Abc_NtkPoNum(pNtk)) { |
| adj[i+1] = adj[i] + Vec_IntSize(oDep[i]); |
| for (k = 0, j = adj[i]; j < adj[i+1]; j++, k++) |
| edg[j] = Vec_IntEntry(oDep[i], k) + Abc_NtkPoNum(pNtk); |
| } |
| else { |
| adj[i+1] = adj[i] + Vec_IntSize(iDep[i-Abc_NtkPoNum(pNtk)]); |
| for (k = 0, j = adj[i]; j < adj[i+1]; j++, k++) |
| edg[j] = Vec_IntEntry(iDep[i-Abc_NtkPoNum(pNtk)], k); |
| } |
| } |
| |
| /* print graph for testing */ |
| /*for (i = 0; i < n; i++) { |
| printf("%d: ", i); |
| for (j = adj[i]; j < adj[i+1]; j++) |
| printf("%d ", edg[j]); |
| printf("\n"); |
| }*/ |
| |
| return g; |
| } |
| |
| static Vec_Int_t * |
| assignRandomBitsToCells(Abc_Ntk_t * pNtk, struct coloring *c) |
| { |
| Vec_Int_t * randVec = Vec_IntAlloc( 1 ); |
| int i, bit; |
| |
| for (i = 0; i < Abc_NtkPiNum(pNtk); i += (c->clen[i+Abc_NtkPoNum(pNtk)]+1)) { |
| bit = (int)(SIM_RANDOM_UNSIGNED % 2); |
| Vec_IntPush(randVec, bit); |
| } |
| |
| return randVec; |
| } |
| |
| static int * |
| generateProperInputVector( Abc_Ntk_t * pNtk, struct coloring *c, Vec_Int_t * randomVector ) |
| { |
| int * vPiValues; |
| int i, j, k, bit, input; |
| int numouts = Abc_NtkPoNum(pNtk); |
| int numins = Abc_NtkPiNum(pNtk); |
| int n = numouts + numins; |
| |
| vPiValues = ABC_ALLOC( int, numins); |
| |
| for (i = numouts, k = 0; i < n; i += (c->clen[i]+1), k++) { |
| if (k == Vec_IntSize(randomVector)) break; |
| |
| bit = Vec_IntEntry(randomVector, k); |
| for (j = i; j <= (i + c->clen[i]); j++) { |
| input = c->lab[j] - numouts; |
| vPiValues[input] = bit; |
| } |
| } |
| |
| //if (k != Vec_IntSize(randomVector)) { |
| if (i < n) { |
| ABC_FREE( vPiValues ); |
| return NULL; |
| } |
| |
| return vPiValues; |
| } |
| |
| static int |
| ifInputVectorsAreConsistent( struct saucy * s, int * leftVec, int * rightVec ) |
| { |
| /* This function assumes that left and right partitions are isomorphic */ |
| int i, j; |
| int lab; |
| int left_bit, right_bit; |
| int numouts = Abc_NtkPoNum(s->pNtk); |
| int n = numouts + Abc_NtkPiNum(s->pNtk); |
| |
| for (i = numouts; i < n; i += (s->right.clen[i]+1)) { |
| lab = s->left.lab[i] - numouts; |
| left_bit = leftVec[lab]; |
| for (j = i+1; j <= (i + s->right.clen[i]); j++) { |
| lab = s->left.lab[j] - numouts; |
| if (left_bit != leftVec[lab]) return -1; |
| } |
| |
| lab = s->right.lab[i] - numouts; |
| right_bit = rightVec[lab]; |
| for (j = i+1; j <= (i + s->right.clen[i]); j++) { |
| lab = s->right.lab[j] - numouts; |
| if (right_bit != rightVec[lab]) return 0; |
| } |
| |
| if (left_bit != right_bit) |
| return 0; |
| } |
| |
| return 1; |
| } |
| |
| static int |
| ifOutputVectorsAreConsistent( struct saucy * s, int * leftVec, int * rightVec ) |
| { |
| /* This function assumes that left and right partitions are isomorphic */ |
| int i, j; |
| int count1, count2; |
| |
| for (i = 0; i < Abc_NtkPoNum(s->pNtk); i += (s->right.clen[i]+1)) { |
| count1 = count2 = 0; |
| for (j = i; j <= (i + s->right.clen[i]); j++) { |
| if (leftVec[s->left.lab[j]]) count1++; |
| if (rightVec[s->right.lab[j]]) count2++; |
| } |
| |
| if (count1 != count2) return 0; |
| } |
| |
| return 1; |
| } |
| |
| static struct saucy_graph * |
| buildSim1Graph( Abc_Ntk_t * pNtk, struct coloring *c, Vec_Int_t * randVec, Vec_Int_t ** iDep, Vec_Int_t ** oDep ) |
| { |
| int i, j, k; |
| struct saucy_graph *g; |
| int n, e, *adj, *edg; |
| int * vPiValues, * output; |
| int numOneOutputs = 0; |
| int numouts = Abc_NtkPoNum(pNtk); |
| int numins = Abc_NtkPiNum(pNtk); |
| |
| vPiValues = generateProperInputVector(pNtk, c, randVec); |
| if (vPiValues == NULL) |
| return NULL; |
| |
| output = Abc_NtkVerifySimulatePattern(pNtk, vPiValues); |
| |
| for (i = 0; i < numouts; i++) { |
| if (output[i]) |
| numOneOutputs++; |
| } |
| |
| g = ABC_ALLOC(struct saucy_graph, 1); |
| n = numouts + numins; |
| e = numins * numOneOutputs; |
| adj = ints(n+1); |
| edg = ints(2*e); |
| g->n = n; |
| g->e = e; |
| g->adj = adj; |
| g->edg = edg; |
| |
| adj[0] = 0; |
| for (i = 0; i < numouts; i++) { |
| if (output[i]) { |
| adj[i+1] = adj[i] + Vec_IntSize(oDep[i]); |
| for (j = adj[i], k = 0; j < adj[i+1]; j++, k++) |
| edg[j] = Vec_IntEntry(oDep[i], k) + numouts; |
| } else { |
| adj[i+1] = adj[i]; |
| } |
| } |
| |
| for (i = 0; i < numins; i++) { |
| adj[i+numouts+1] = adj[i+numouts]; |
| for (k = 0, j = adj[i+numouts]; k < Vec_IntSize(iDep[i]); k++) { |
| if (output[Vec_IntEntry(iDep[i], k)]) { |
| edg[j++] = Vec_IntEntry(iDep[i], k); |
| adj[i+numouts+1]++; |
| } |
| } |
| } |
| |
| /* print graph */ |
| /*for (i = 0; i < n; i++) { |
| printf("%d: ", i); |
| for (j = adj[i]; j < adj[i+1]; j++) |
| printf("%d ", edg[j]); |
| printf("\n"); |
| }*/ |
| |
| ABC_FREE( vPiValues ); |
| ABC_FREE( output ); |
| |
| return g; |
| } |
| |
| static struct saucy_graph * |
| buildSim2Graph( Abc_Ntk_t * pNtk, struct coloring *c, Vec_Int_t * randVec, Vec_Int_t ** iDep, Vec_Int_t ** oDep, Vec_Ptr_t ** topOrder, Vec_Int_t ** obs, Vec_Int_t ** ctrl ) |
| { |
| int i, j, k; |
| struct saucy_graph *g = NULL; |
| int n, e = 0, *adj, *edg; |
| int * vPiValues; |
| int * output, * output2; |
| int numouts = Abc_NtkPoNum(pNtk); |
| int numins = Abc_NtkPiNum(pNtk); |
| |
| extern int * Abc_NtkSimulateOneNode( Abc_Ntk_t * , int * , int , Vec_Ptr_t ** ); |
| |
| vPiValues = generateProperInputVector(pNtk, c, randVec); |
| if (vPiValues == NULL) |
| return NULL; |
| |
| output = Abc_NtkVerifySimulatePattern( pNtk, vPiValues ); |
| |
| for (i = 0; i < numins; i++) { |
| if (!c->clen[c->cfront[i+numouts]]) continue; |
| if (vPiValues[i] == 0) vPiValues[i] = 1; |
| else vPiValues[i] = 0; |
| |
| output2 = Abc_NtkSimulateOneNode( pNtk, vPiValues, i, topOrder ); |
| |
| for (j = 0; j < Vec_IntSize(iDep[i]); j++) { |
| if (output[Vec_IntEntry(iDep[i], j)] != output2[Vec_IntEntry(iDep[i], j)]) { |
| Vec_IntPush(obs[i], Vec_IntEntry(iDep[i], j)); |
| Vec_IntPush(ctrl[Vec_IntEntry(iDep[i], j)], i); |
| e++; |
| } |
| } |
| |
| if (vPiValues[i] == 0) vPiValues[i] = 1; |
| else vPiValues[i] = 0; |
| |
| ABC_FREE( output2 ); |
| } |
| |
| /* build the graph */ |
| g = ABC_ALLOC(struct saucy_graph, 1); |
| n = numouts + numins; |
| adj = ints(n+1); |
| edg = ints(2*e); |
| g->n = n; |
| g->e = e; |
| g->adj = adj; |
| g->edg = edg; |
| |
| adj[0] = 0; |
| for (i = 0; i < numouts; i++) { |
| adj[i+1] = adj[i] + Vec_IntSize(ctrl[i]); |
| for (k = 0, j = adj[i]; j < adj[i+1]; j++, k++) |
| edg[j] = Vec_IntEntry(ctrl[i], k) + numouts; |
| } |
| for (i = 0; i < numins; i++) { |
| adj[i+numouts+1] = adj[i+numouts] + Vec_IntSize(obs[i]); |
| for (k = 0, j = adj[i+numouts]; j < adj[i+numouts+1]; j++, k++) |
| edg[j] = Vec_IntEntry(obs[i], k); |
| } |
| |
| /* print graph */ |
| /*for (i = 0; i < n; i++) { |
| printf("%d: ", i); |
| for (j = adj[i]; j < adj[i+1]; j++) |
| printf("%d ", edg[j]); |
| printf("\n"); |
| }*/ |
| |
| ABC_FREE( output ); |
| ABC_FREE( vPiValues ); |
| for (j = 0; j < numins; j++) |
| Vec_IntClear(obs[j]); |
| for (j = 0; j < numouts; j++) |
| Vec_IntClear(ctrl[j]); |
| |
| return g; |
| } |
| |
| static void |
| bumpActivity( struct saucy * s, struct sim_result * cex ) |
| { |
| int i; |
| struct sim_result * cex2; |
| |
| if ( (cex->activity += s->activityInc) > 1e20 ) { |
| /* Rescale: */ |
| for (i = 0; i < Vec_PtrSize(s->satCounterExamples); i++) { |
| cex2 = (struct sim_result *)Vec_PtrEntry(s->satCounterExamples, i); |
| cex2->activity *= 1e-20; |
| } |
| s->activityInc *= 1e-20; |
| } |
| } |
| |
| static void |
| reduceDB( struct saucy * s ) |
| { |
| int i, j; |
| double extra_lim = s->activityInc / Vec_PtrSize(s->satCounterExamples); /* Remove any clause below this activity */ |
| struct sim_result * cex; |
| |
| while (Vec_PtrSize(s->satCounterExamples) > (0.7 * MAX_LEARNTS)) { |
| for (i = j = 0; i < Vec_PtrSize(s->satCounterExamples); i++) { |
| cex = (struct sim_result *)Vec_PtrEntry(s->satCounterExamples, i); |
| if (cex->activity < extra_lim) { |
| ABC_FREE(cex->inVec); |
| ABC_FREE(cex->outVec); |
| ABC_FREE(cex); |
| } |
| else if (j < i) { |
| Vec_PtrWriteEntry(s->satCounterExamples, j, cex); |
| j++; |
| } |
| } |
| //printf("Database size reduced from %d to %d\n", Vec_PtrSize(s->satCounterExamples), j); |
| Vec_PtrShrink(s->satCounterExamples, j); |
| extra_lim *= 2; |
| } |
| |
| assert(Vec_PtrSize(s->satCounterExamples) <= (0.7 * MAX_LEARNTS)); |
| } |
| |
| static struct sim_result * |
| analyzeConflict( Abc_Ntk_t * pNtk, int * pModel, int fVerbose ) |
| { |
| Abc_Obj_t * pNode; |
| int i, count = 0; |
| int * pValues; |
| struct sim_result * cex; |
| int numouts = Abc_NtkPoNum(pNtk); |
| int numins = Abc_NtkPiNum(pNtk); |
| |
| cex = ABC_ALLOC(struct sim_result, 1); |
| cex->inVec = ints( numins ); |
| cex->outVec = ints( numouts ); |
| |
| /* get the CO values under this model */ |
| pValues = Abc_NtkVerifySimulatePattern( pNtk, pModel ); |
| |
| Abc_NtkForEachCi( pNtk, pNode, i ) |
| cex->inVec[Abc_ObjId(pNode)-1] = pModel[i]; |
| Abc_NtkForEachCo( pNtk, pNode, i ) { |
| cex->outVec[Abc_ObjId(pNode)-numins-1] = pValues[i]; |
| if (pValues[i]) count++; |
| } |
| |
| cex->outVecOnes = count; |
| cex->activity = 0; |
| |
| if (fVerbose) { |
| Abc_NtkForEachCi( pNtk, pNode, i ) |
| printf(" %s=%d", Abc_ObjName(pNode), pModel[i]); |
| printf("\n"); |
| } |
| |
| ABC_FREE( pValues ); |
| |
| return cex; |
| } |
| |
| static int |
| Abc_NtkCecSat_saucy( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, int * pModel ) |
| { |
| extern Abc_Ntk_t * Abc_NtkMulti( Abc_Ntk_t * pNtk, int nThresh, int nFaninMax, int fCnf, int fMulti, int fSimple, int fFactor ); |
| Abc_Ntk_t * pMiter; |
| Abc_Ntk_t * pCnf; |
| int RetValue; |
| int nConfLimit; |
| int nInsLimit; |
| int i; |
| |
| nConfLimit = 10000; |
| nInsLimit = 0; |
| |
| /* get the miter of the two networks */ |
| pMiter = Abc_NtkMiter( pNtk1, pNtk2, 1, 0, 0, 0 ); |
| if ( pMiter == NULL ) |
| { |
| printf( "Miter computation has failed.\n" ); |
| exit(1); |
| } |
| RetValue = Abc_NtkMiterIsConstant( pMiter ); |
| if ( RetValue == 0 ) |
| { |
| //printf( "Networks are NOT EQUIVALENT after structural hashing.\n" ); |
| /* report the error */ |
| pMiter->pModel = Abc_NtkVerifyGetCleanModel( pMiter, 1 ); |
| for (i = 0; i < Abc_NtkPiNum(pNtk1); i++) |
| pModel[i] = pMiter->pModel[i]; |
| ABC_FREE( pMiter->pModel ); |
| Abc_NtkDelete( pMiter ); |
| return 0; |
| } |
| if ( RetValue == 1 ) |
| { |
| Abc_NtkDelete( pMiter ); |
| //printf( "Networks are equivalent after structural hashing.\n" ); |
| return 1; |
| } |
| |
| /* convert the miter into a CNF */ |
| pCnf = Abc_NtkMulti( pMiter, 0, 100, 1, 0, 0, 0 ); |
| Abc_NtkDelete( pMiter ); |
| if ( pCnf == NULL ) |
| { |
| printf( "Renoding for CNF has failed.\n" ); |
| exit(1); |
| } |
| |
| /* solve the CNF using the SAT solver */ |
| RetValue = Abc_NtkMiterSat( pCnf, (ABC_INT64_T)nConfLimit, (ABC_INT64_T)nInsLimit, 0, NULL, NULL ); |
| if ( RetValue == -1 ) { |
| printf( "Networks are undecided (SAT solver timed out).\n" ); |
| exit(1); |
| } |
| /*else if ( RetValue == 0 ) |
| printf( "Networks are NOT EQUIVALENT after SAT.\n" ); |
| else |
| printf( "Networks are equivalent after SAT.\n" );*/ |
| if ( pCnf->pModel ) { |
| for (i = 0; i < Abc_NtkPiNum(pNtk1); i++) |
| pModel[i] = pCnf->pModel[i]; |
| } |
| ABC_FREE( pCnf->pModel ); |
| Abc_NtkDelete( pCnf ); |
| |
| return RetValue; |
| } |
| |
| |
| void saucyGateWay( Abc_Ntk_t * pNtkOrig, Abc_Obj_t * pNodePo, FILE * gFile, int fBooleanMatching, |
| int fLookForSwaps, int fFixOutputs, int fFixInputs, int fQuiet, int fPrintTree ) |
| { |
| Abc_Ntk_t * pNtk; |
| struct saucy *s; |
| struct saucy_stats stats; |
| int *colors; |
| int i, clk = clock(); |
| |
| if (pNodePo == NULL) |
| pNtk = Abc_NtkDup( pNtkOrig ); |
| else |
| pNtk = Abc_NtkCreateCone( pNtkOrig, Abc_ObjFanin0(pNodePo), Abc_ObjName(pNodePo), 0 ); |
| |
| if (Abc_NtkPiNum(pNtk) == 0) { |
| Abc_Print( 0, "This output is not dependent on any input\n" ); |
| Abc_NtkDelete( pNtk ); |
| return; |
| } |
| |
| s = saucy_alloc( pNtk ); |
| |
| /******* Getting Dependencies *******/ |
| printf("Build functional dependency graph (dependency stats are below) ... "); |
| getDependencies( pNtk, s->iDep, s->oDep ); |
| printf("\t--------------------\n"); |
| /************************************/ |
| |
| /* Finding toplogical orde */ |
| s->topOrder = findTopologicalOrder( pNtk ); |
| |
| /* Setting graph colors: outputs = 0 and inputs = 1 */ |
| colors = ints(Abc_NtkPoNum(pNtk) + Abc_NtkPiNum(pNtk)); |
| if (fFixOutputs) { |
| for (i = 0; i < Abc_NtkPoNum(pNtk); i++) |
| colors[i] = i; |
| } else { |
| for (i = 0; i < Abc_NtkPoNum(pNtk); i++) |
| colors[i] = 0; |
| } |
| if (fFixInputs) { |
| int c = (fFixOutputs) ? Abc_NtkPoNum(pNtk) : 1; |
| for (i = 0; i < Abc_NtkPiNum(pNtk); i++) |
| colors[i+Abc_NtkPoNum(pNtk)] = c+i; |
| } else { |
| int c = (fFixOutputs) ? Abc_NtkPoNum(pNtk) : 1; |
| for (i = 0; i < Abc_NtkPiNum(pNtk); i++) |
| colors[i+Abc_NtkPoNum(pNtk)] = c; |
| } |
| |
| /* Are we looking for Boolean matching? */ |
| s->fBooleanMatching = fBooleanMatching; |
| if (fBooleanMatching) { |
| NUM_SIM1_ITERATION = 50; |
| NUM_SIM2_ITERATION = 50; |
| } else { |
| NUM_SIM1_ITERATION = 200; |
| NUM_SIM2_ITERATION = 200; |
| } |
| |
| /* Set the print automorphism routine */ |
| if (!fQuiet) |
| s->print_automorphism = print_automorphism_ntk; |
| else |
| s->print_automorphism = print_automorphism_quiet; |
| |
| /* Set the output file for generators */ |
| if (gFile == NULL) |
| s->gFile = stdout; |
| else |
| s->gFile = gFile; |
| |
| /* Set print tree option */ |
| s->fPrintTree = fPrintTree; |
| |
| /* Set input permutations option */ |
| s->fLookForSwaps = fLookForSwaps; |
| |
| saucy_search(pNtk, s, 0, colors, &stats); |
| print_stats(stdout, stats); |
| if (fBooleanMatching) { |
| if (stats.grpsize_base > 1 || stats.grpsize_exp > 0) |
| printf("*** Networks are equivalent ***\n"); |
| else |
| printf("*** Networks are NOT equivalent ***\n"); |
| } |
| saucy_free(s); |
| Abc_NtkDelete(pNtk); |
| |
| if (1) { |
| FILE * hadi = fopen("hadi.txt", "a"); |
| fprintf(hadi, "group size = %fe%d\n", |
| stats.grpsize_base, stats.grpsize_exp); |
| fclose(hadi); |
| } |
| |
| ABC_PRT( "Runtime", clock() - clk ); |
| |
| }ABC_NAMESPACE_IMPL_END |
| |
| |