From 4812c90424dfc40d26725244723887a2d16ddfd9 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 1 Oct 2007 08:01:00 -0700 Subject: Version abc71001 --- src/misc/espresso/cofactor.c | 382 ++++++ src/misc/espresso/cols.c | 314 +++++ src/misc/espresso/compl.c | 680 +++++++++++ src/misc/espresso/contain.c | 441 +++++++ src/misc/espresso/cubehack.c | 138 +++ src/misc/espresso/cubestr.c | 152 +++ src/misc/espresso/cvrin.c | 810 +++++++++++++ src/misc/espresso/cvrm.c | 539 +++++++++ src/misc/espresso/cvrmisc.c | 142 +++ src/misc/espresso/cvrout.c | 609 ++++++++++ src/misc/espresso/dominate.c | 98 ++ src/misc/espresso/equiv.c | 94 ++ src/misc/espresso/espresso.c | 139 +++ src/misc/espresso/espresso.h | 782 ++++++++++++ src/misc/espresso/essen.c | 179 +++ src/misc/espresso/exact.c | 181 +++ src/misc/espresso/expand.c | 693 +++++++++++ src/misc/espresso/gasp.c | 228 ++++ src/misc/espresso/gimpel.c | 106 ++ src/misc/espresso/globals.c | 76 ++ src/misc/espresso/hack.c | 641 ++++++++++ src/misc/espresso/indep.c | 134 +++ src/misc/espresso/irred.c | 440 +++++++ src/misc/espresso/main.c | 746 ++++++++++++ src/misc/espresso/main.h | 122 ++ src/misc/espresso/map.c | 115 ++ src/misc/espresso/matrix.c | 574 +++++++++ src/misc/espresso/mincov.c | 378 ++++++ src/misc/espresso/mincov.h | 11 + src/misc/espresso/mincov_int.h | 55 + src/misc/espresso/module.make | 39 + src/misc/espresso/opo.c | 624 ++++++++++ src/misc/espresso/pair.c | 675 +++++++++++ src/misc/espresso/part.c | 122 ++ src/misc/espresso/primes.c | 170 +++ src/misc/espresso/reduce.c | 258 ++++ src/misc/espresso/rows.c | 314 +++++ src/misc/espresso/set.c | 820 +++++++++++++ src/misc/espresso/setc.c | 483 ++++++++ src/misc/espresso/sharp.c | 247 ++++ src/misc/espresso/sminterf.c | 44 + src/misc/espresso/solution.c | 114 ++ src/misc/espresso/sparse.c | 146 +++ src/misc/espresso/sparse.h | 135 +++ src/misc/espresso/sparse_int.h | 121 ++ src/misc/espresso/unate.c | 441 +++++++ src/misc/espresso/util_old.h | 301 +++++ src/misc/espresso/verify.c | 193 +++ src/misc/extra/extra.h | 626 ++++++++++ src/misc/extra/extraBddAuto.c | 1558 ++++++++++++++++++++++++ src/misc/extra/extraBddCas.c | 1230 +++++++++++++++++++ src/misc/extra/extraBddKmap.c | 783 ++++++++++++ src/misc/extra/extraBddMisc.c | 1614 +++++++++++++++++++++++++ src/misc/extra/extraBddSymm.c | 1469 +++++++++++++++++++++++ src/misc/extra/extraBddUnate.c | 641 ++++++++++ src/misc/extra/extraUtilBitMatrix.c | 415 +++++++ src/misc/extra/extraUtilCanon.c | 701 +++++++++++ src/misc/extra/extraUtilFile.c | 495 ++++++++ src/misc/extra/extraUtilMemory.c | 625 ++++++++++ src/misc/extra/extraUtilMisc.c | 2235 +++++++++++++++++++++++++++++++++++ src/misc/extra/extraUtilProgress.c | 176 +++ src/misc/extra/extraUtilReader.c | 383 ++++++ src/misc/extra/extraUtilTruth.c | 1148 ++++++++++++++++++ src/misc/extra/extraUtilUtil.c | 330 ++++++ src/misc/extra/module.make | 15 + src/misc/hash/hash.h | 65 + src/misc/hash/hashFlt.h | 330 ++++++ src/misc/hash/hashInt.h | 293 +++++ src/misc/hash/hashPtr.h | 331 ++++++ src/misc/hash/module.make | 1 + src/misc/mvc/module.make | 16 + src/misc/mvc/mvc.c | 46 + src/misc/mvc/mvc.h | 732 ++++++++++++ src/misc/mvc/mvcApi.c | 233 ++++ src/misc/mvc/mvcCompare.c | 369 ++++++ src/misc/mvc/mvcContain.c | 173 +++ src/misc/mvc/mvcCover.c | 251 ++++ src/misc/mvc/mvcCube.c | 175 +++ src/misc/mvc/mvcDivide.c | 436 +++++++ src/misc/mvc/mvcDivisor.c | 90 ++ src/misc/mvc/mvcList.c | 362 ++++++ src/misc/mvc/mvcLits.c | 345 ++++++ src/misc/mvc/mvcMan.c | 77 ++ src/misc/mvc/mvcOpAlg.c | 163 +++ src/misc/mvc/mvcOpBool.c | 151 +++ src/misc/mvc/mvcPrint.c | 220 ++++ src/misc/mvc/mvcSort.c | 141 +++ src/misc/mvc/mvcUtils.c | 868 ++++++++++++++ src/misc/nm/module.make | 2 + src/misc/nm/nm.h | 92 ++ src/misc/nm/nmApi.c | 272 +++++ src/misc/nm/nmInt.h | 91 ++ src/misc/nm/nmTable.c | 340 ++++++ src/misc/st/module.make | 2 + src/misc/st/st.c | 625 ++++++++++ src/misc/st/st.h | 96 ++ src/misc/st/stmm.c | 688 +++++++++++ src/misc/st/stmm.h | 127 ++ src/misc/util/leaks.h | 30 + src/misc/util/module.make | 1 + src/misc/util/stdlib_hack.h | 4 + src/misc/util/util_hack.h | 95 ++ src/misc/vec/module.make | 1 + src/misc/vec/vec.h | 121 ++ src/misc/vec/vecAtt.h | 391 ++++++ src/misc/vec/vecFlt.h | 630 ++++++++++ src/misc/vec/vecInt.h | 834 +++++++++++++ src/misc/vec/vecPtr.h | 762 ++++++++++++ src/misc/vec/vecStr.h | 583 +++++++++ src/misc/vec/vecVec.h | 356 ++++++ 110 files changed, 41701 insertions(+) create mode 100644 src/misc/espresso/cofactor.c create mode 100644 src/misc/espresso/cols.c create mode 100644 src/misc/espresso/compl.c create mode 100644 src/misc/espresso/contain.c create mode 100644 src/misc/espresso/cubehack.c create mode 100644 src/misc/espresso/cubestr.c create mode 100644 src/misc/espresso/cvrin.c create mode 100644 src/misc/espresso/cvrm.c create mode 100644 src/misc/espresso/cvrmisc.c create mode 100644 src/misc/espresso/cvrout.c create mode 100644 src/misc/espresso/dominate.c create mode 100644 src/misc/espresso/equiv.c create mode 100644 src/misc/espresso/espresso.c create mode 100644 src/misc/espresso/espresso.h create mode 100644 src/misc/espresso/essen.c create mode 100644 src/misc/espresso/exact.c create mode 100644 src/misc/espresso/expand.c create mode 100644 src/misc/espresso/gasp.c create mode 100644 src/misc/espresso/gimpel.c create mode 100644 src/misc/espresso/globals.c create mode 100644 src/misc/espresso/hack.c create mode 100644 src/misc/espresso/indep.c create mode 100644 src/misc/espresso/irred.c create mode 100644 src/misc/espresso/main.c create mode 100644 src/misc/espresso/main.h create mode 100644 src/misc/espresso/map.c create mode 100644 src/misc/espresso/matrix.c create mode 100644 src/misc/espresso/mincov.c create mode 100644 src/misc/espresso/mincov.h create mode 100644 src/misc/espresso/mincov_int.h create mode 100644 src/misc/espresso/module.make create mode 100644 src/misc/espresso/opo.c create mode 100644 src/misc/espresso/pair.c create mode 100644 src/misc/espresso/part.c create mode 100644 src/misc/espresso/primes.c create mode 100644 src/misc/espresso/reduce.c create mode 100644 src/misc/espresso/rows.c create mode 100644 src/misc/espresso/set.c create mode 100644 src/misc/espresso/setc.c create mode 100644 src/misc/espresso/sharp.c create mode 100644 src/misc/espresso/sminterf.c create mode 100644 src/misc/espresso/solution.c create mode 100644 src/misc/espresso/sparse.c create mode 100644 src/misc/espresso/sparse.h create mode 100644 src/misc/espresso/sparse_int.h create mode 100644 src/misc/espresso/unate.c create mode 100644 src/misc/espresso/util_old.h create mode 100644 src/misc/espresso/verify.c create mode 100644 src/misc/extra/extra.h create mode 100644 src/misc/extra/extraBddAuto.c create mode 100644 src/misc/extra/extraBddCas.c create mode 100644 src/misc/extra/extraBddKmap.c create mode 100644 src/misc/extra/extraBddMisc.c create mode 100644 src/misc/extra/extraBddSymm.c create mode 100644 src/misc/extra/extraBddUnate.c create mode 100644 src/misc/extra/extraUtilBitMatrix.c create mode 100644 src/misc/extra/extraUtilCanon.c create mode 100644 src/misc/extra/extraUtilFile.c create mode 100644 src/misc/extra/extraUtilMemory.c create mode 100644 src/misc/extra/extraUtilMisc.c create mode 100644 src/misc/extra/extraUtilProgress.c create mode 100644 src/misc/extra/extraUtilReader.c create mode 100644 src/misc/extra/extraUtilTruth.c create mode 100644 src/misc/extra/extraUtilUtil.c create mode 100644 src/misc/extra/module.make create mode 100644 src/misc/hash/hash.h create mode 100644 src/misc/hash/hashFlt.h create mode 100644 src/misc/hash/hashInt.h create mode 100644 src/misc/hash/hashPtr.h create mode 100644 src/misc/hash/module.make create mode 100644 src/misc/mvc/module.make create mode 100644 src/misc/mvc/mvc.c create mode 100644 src/misc/mvc/mvc.h create mode 100644 src/misc/mvc/mvcApi.c create mode 100644 src/misc/mvc/mvcCompare.c create mode 100644 src/misc/mvc/mvcContain.c create mode 100644 src/misc/mvc/mvcCover.c create mode 100644 src/misc/mvc/mvcCube.c create mode 100644 src/misc/mvc/mvcDivide.c create mode 100644 src/misc/mvc/mvcDivisor.c create mode 100644 src/misc/mvc/mvcList.c create mode 100644 src/misc/mvc/mvcLits.c create mode 100644 src/misc/mvc/mvcMan.c create mode 100644 src/misc/mvc/mvcOpAlg.c create mode 100644 src/misc/mvc/mvcOpBool.c create mode 100644 src/misc/mvc/mvcPrint.c create mode 100644 src/misc/mvc/mvcSort.c create mode 100644 src/misc/mvc/mvcUtils.c create mode 100644 src/misc/nm/module.make create mode 100644 src/misc/nm/nm.h create mode 100644 src/misc/nm/nmApi.c create mode 100644 src/misc/nm/nmInt.h create mode 100644 src/misc/nm/nmTable.c create mode 100644 src/misc/st/module.make create mode 100644 src/misc/st/st.c create mode 100644 src/misc/st/st.h create mode 100644 src/misc/st/stmm.c create mode 100644 src/misc/st/stmm.h create mode 100644 src/misc/util/leaks.h create mode 100644 src/misc/util/module.make create mode 100644 src/misc/util/stdlib_hack.h create mode 100644 src/misc/util/util_hack.h create mode 100644 src/misc/vec/module.make create mode 100644 src/misc/vec/vec.h create mode 100644 src/misc/vec/vecAtt.h create mode 100644 src/misc/vec/vecFlt.h create mode 100644 src/misc/vec/vecInt.h create mode 100644 src/misc/vec/vecPtr.h create mode 100644 src/misc/vec/vecStr.h create mode 100644 src/misc/vec/vecVec.h (limited to 'src/misc') diff --git a/src/misc/espresso/cofactor.c b/src/misc/espresso/cofactor.c new file mode 100644 index 00000000..b851a639 --- /dev/null +++ b/src/misc/espresso/cofactor.c @@ -0,0 +1,382 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +#include "espresso.h" + +/* + The cofactor of a cover against a cube "c" is a cover formed by the + cofactor of each cube in the cover against c. The cofactor of two + cubes is null if they are distance 1 or more apart. If they are + distance zero apart, the cofactor is the restriction of the cube + to the minterms of c. + + The cube list contains the following information: + + T[0] = pointer to a cube identifying the variables that have + been cofactored against + T[1] = pointer to just beyond the sentinel (i.e., T[n] in this case) + T[2] + . + . = pointers to cubes + . + T[n-2] + T[n-1] = NULL pointer (sentinel) + + + Cofactoring involves repeated application of "cdist0" to check if a + cube of the cover intersects the cofactored cube. This can be + slow, especially for the recursive descent of the espresso + routines. Therefore, a special cofactor routine "scofactor" is + provided which assumes the cofactor is only in a single variable. +*/ + + +/* cofactor -- compute the cofactor of a cover with respect to a cube */ +pcube *cofactor(T, c) +IN pcube *T; +IN register pcube c; +{ + pcube temp = cube.temp[0], *Tc_save, *Tc, *T1; + register pcube p; + int listlen; + + listlen = CUBELISTSIZE(T) + 5; + + /* Allocate a new list of cube pointers (max size is previous size) */ + Tc_save = Tc = ALLOC(pcube, listlen); + + /* pass on which variables have been cofactored against */ + *Tc++ = set_or(new_cube(), T[0], set_diff(temp, cube.fullset, c)); + Tc++; + + /* Loop for each cube in the list, determine suitability, and save */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (p != c) { + +#ifdef NO_INLINE + if (! cdist0(p, c)) goto false; +#else + {register int w,last;register unsigned int x;if((last=cube.inword)!=-1) + {x=p[last]&c[last];if(~(x|x>>1)&cube.inmask)goto false;for(w=1;w>1)&DISJOINT)goto false;}}}{register int w,var,last; + register pcube mask;for(var=cube.num_binary_vars;var= 0; i--) + count[i] = 0; + } + + /* Count the number of zeros in each column */ + { register int i, *cnt; + register unsigned int val; + register pcube p, cof = T[0], full = cube.fullset; + for(T1 = T+2; (p = *T1++) != NULL; ) + for(i = LOOP(p); i > 0; i--) + if (val = full[i] & ~ (p[i] | cof[i])) { + cnt = count + ((i-1) << LOGBPI); +#if BPI == 32 + if (val & 0xFF000000) { + if (val & 0x80000000) cnt[31]++; + if (val & 0x40000000) cnt[30]++; + if (val & 0x20000000) cnt[29]++; + if (val & 0x10000000) cnt[28]++; + if (val & 0x08000000) cnt[27]++; + if (val & 0x04000000) cnt[26]++; + if (val & 0x02000000) cnt[25]++; + if (val & 0x01000000) cnt[24]++; + } + if (val & 0x00FF0000) { + if (val & 0x00800000) cnt[23]++; + if (val & 0x00400000) cnt[22]++; + if (val & 0x00200000) cnt[21]++; + if (val & 0x00100000) cnt[20]++; + if (val & 0x00080000) cnt[19]++; + if (val & 0x00040000) cnt[18]++; + if (val & 0x00020000) cnt[17]++; + if (val & 0x00010000) cnt[16]++; + } +#endif + if (val & 0xFF00) { + if (val & 0x8000) cnt[15]++; + if (val & 0x4000) cnt[14]++; + if (val & 0x2000) cnt[13]++; + if (val & 0x1000) cnt[12]++; + if (val & 0x0800) cnt[11]++; + if (val & 0x0400) cnt[10]++; + if (val & 0x0200) cnt[ 9]++; + if (val & 0x0100) cnt[ 8]++; + } + if (val & 0x00FF) { + if (val & 0x0080) cnt[ 7]++; + if (val & 0x0040) cnt[ 6]++; + if (val & 0x0020) cnt[ 5]++; + if (val & 0x0010) cnt[ 4]++; + if (val & 0x0008) cnt[ 3]++; + if (val & 0x0004) cnt[ 2]++; + if (val & 0x0002) cnt[ 1]++; + if (val & 0x0001) cnt[ 0]++; + } + } + } + + /* + * Perform counts for each variable: + * cdata.var_zeros[var] = number of zeros in the variable + * cdata.parts_active[var] = number of active parts for each variable + * cdata.vars_active = number of variables which are active + * cdata.vars_unate = number of variables which are active and unate + * + * best -- the variable which is best for splitting based on: + * mostactive -- most # active parts in any variable + * mostzero -- most # zeros in any variable + * mostbalanced -- minimum over the maximum # zeros / part / variable + */ + + { register int var, i, lastbit, active, maxactive; + int best = -1, mostactive = 0, mostzero = 0, mostbalanced = 32000; + cdata.vars_unate = cdata.vars_active = 0; + + for(var = 0; var < cube.num_vars; var++) { + if (var < cube.num_binary_vars) { /* special hack for binary vars */ + i = count[var*2]; + lastbit = count[var*2 + 1]; + active = (i > 0) + (lastbit > 0); + cdata.var_zeros[var] = i + lastbit; + maxactive = MAX(i, lastbit); + } else { + maxactive = active = cdata.var_zeros[var] = 0; + lastbit = cube.last_part[var]; + for(i = cube.first_part[var]; i <= lastbit; i++) { + cdata.var_zeros[var] += count[i]; + active += (count[i] > 0); + if (active > maxactive) maxactive = active; + } + } + + /* first priority is to maximize the number of active parts */ + /* for binary case, this will usually select the output first */ + if (active > mostactive) + best = var, mostactive = active, mostzero = cdata.var_zeros[best], + mostbalanced = maxactive; + else if (active == mostactive) + /* secondary condition is to maximize the number zeros */ + /* for binary variables, this is the same as minimum # of 2's */ + if (cdata.var_zeros[var] > mostzero) + best = var, mostzero = cdata.var_zeros[best], + mostbalanced = maxactive; + else if (cdata.var_zeros[var] == mostzero) + /* third condition is to pick a balanced variable */ + /* for binary vars, this means roughly equal # 0's and 1's */ + if (maxactive < mostbalanced) + best = var, mostbalanced = maxactive; + + cdata.parts_active[var] = active; + cdata.is_unate[var] = (active == 1); + cdata.vars_active += (active > 0); + cdata.vars_unate += (active == 1); + } + cdata.best = best; + } +} + +int binate_split_select(T, cleft, cright, debug_flag) +IN pcube *T; +IN register pcube cleft, cright; +IN int debug_flag; +{ + int best = cdata.best; + register int i, lastbit = cube.last_part[best], halfbit = 0; + register pcube cof=T[0]; + + /* Create the cubes to cofactor against */ + (void) set_diff(cleft, cube.fullset, cube.var_mask[best]); + (void) set_diff(cright, cube.fullset, cube.var_mask[best]); + for(i = cube.first_part[best]; i <= lastbit; i++) + if (! is_in_set(cof,i)) + halfbit++; + for(i = cube.first_part[best], halfbit = halfbit/2; halfbit > 0; i++) + if (! is_in_set(cof,i)) + halfbit--, set_insert(cleft, i); + for(; i <= lastbit; i++) + if (! is_in_set(cof,i)) + set_insert(cright, i); + + if (debug & debug_flag) { + (void) printf("BINATE_SPLIT_SELECT: split against %d\n", best); + if (verbose_debug) + (void) printf("cl=%s\ncr=%s\n", pc1(cleft), pc2(cright)); + } + return best; +} + + +pcube *cube1list(A) +pcover A; +{ + register pcube last, p, *plist, *list; + + list = plist = ALLOC(pcube, A->count + 3); + *plist++ = new_cube(); + plist++; + foreach_set(A, last, p) { + *plist++ = p; + } + *plist++ = NULL; /* sentinel */ + list[1] = (pcube) plist; + return list; +} + + +pcube *cube2list(A, B) +pcover A, B; +{ + register pcube last, p, *plist, *list; + + list = plist = ALLOC(pcube, A->count + B->count + 3); + *plist++ = new_cube(); + plist++; + foreach_set(A, last, p) { + *plist++ = p; + } + foreach_set(B, last, p) { + *plist++ = p; + } + *plist++ = NULL; + list[1] = (pcube) plist; + return list; +} + + +pcube *cube3list(A, B, C) +pcover A, B, C; +{ + register pcube last, p, *plist, *list; + + plist = ALLOC(pcube, A->count + B->count + C->count + 3); + list = plist; + *plist++ = new_cube(); + plist++; + foreach_set(A, last, p) { + *plist++ = p; + } + foreach_set(B, last, p) { + *plist++ = p; + } + foreach_set(C, last, p) { + *plist++ = p; + } + *plist++ = NULL; + list[1] = (pcube) plist; + return list; +} + + +pcover cubeunlist(A1) +pcube *A1; +{ + register int i; + register pcube p, pdest, cof = A1[0]; + register pcover A; + + A = new_cover(CUBELISTSIZE(A1)); + for(i = 2; (p = A1[i]) != NULL; i++) { + pdest = GETSET(A, i-2); + INLINEset_or(pdest, p, cof); + } + A->count = CUBELISTSIZE(A1); + return A; +} + +simplify_cubelist(T) +pcube *T; +{ + register pcube *Tdest; + register int i, ncubes; + + (void) set_copy(cube.temp[0], T[0]); /* retrieve cofactor */ + + ncubes = CUBELISTSIZE(T); + qsort((char *) (T+2), ncubes, sizeof(pset), (int (*)()) d1_order); + + Tdest = T+2; + /* *Tdest++ = T[2]; */ + for(i = 3; i < ncubes; i++) { + if (d1_order(&T[i-1], &T[i]) != 0) { + *Tdest++ = T[i]; + } + } + + *Tdest++ = NULL; /* sentinel */ + Tdest[1] = (pcube) Tdest; /* save pointer to last */ +} diff --git a/src/misc/espresso/cols.c b/src/misc/espresso/cols.c new file mode 100644 index 00000000..ec3797e6 --- /dev/null +++ b/src/misc/espresso/cols.c @@ -0,0 +1,314 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +//#include "port.h" +#include "sparse_int.h" + + +/* + * allocate a new col vector + */ +sm_col * +sm_col_alloc() +{ + register sm_col *pcol; + +#ifdef FAST_AND_LOOSE + if (sm_col_freelist == NIL(sm_col)) { + pcol = ALLOC(sm_col, 1); + } else { + pcol = sm_col_freelist; + sm_col_freelist = pcol->next_col; + } +#else + pcol = ALLOC(sm_col, 1); +#endif + + pcol->col_num = 0; + pcol->length = 0; + pcol->first_row = pcol->last_row = NIL(sm_element); + pcol->next_col = pcol->prev_col = NIL(sm_col); + pcol->flag = 0; + pcol->user_word = NIL(char); /* for our user ... */ + return pcol; +} + + +/* + * free a col vector -- for FAST_AND_LOOSE, this is real cheap for cols; + * however, freeing a rowumn must still walk down the rowumn discarding + * the elements one-by-one; that is the only use for the extra '-DCOLS' + * compile flag ... + */ +void +sm_col_free(pcol) +register sm_col *pcol; +{ +#if defined(FAST_AND_LOOSE) && ! defined(COLS) + if (pcol->first_row != NIL(sm_element)) { + /* Add the linked list of col items to the free list */ + pcol->last_row->next_row = sm_element_freelist; + sm_element_freelist = pcol->first_row; + } + + /* Add the col to the free list of cols */ + pcol->next_col = sm_col_freelist; + sm_col_freelist = pcol; +#else + register sm_element *p, *pnext; + + for(p = pcol->first_row; p != 0; p = pnext) { + pnext = p->next_row; + sm_element_free(p); + } + FREE(pcol); +#endif +} + + +/* + * duplicate an existing col + */ +sm_col * +sm_col_dup(pcol) +register sm_col *pcol; +{ + register sm_col *pnew; + register sm_element *p; + + pnew = sm_col_alloc(); + for(p = pcol->first_row; p != 0; p = p->next_row) { + (void) sm_col_insert(pnew, p->row_num); + } + return pnew; +} + + +/* + * insert an element into a col vector + */ +sm_element * +sm_col_insert(pcol, row) +register sm_col *pcol; +register int row; +{ + register sm_element *test, *element; + + /* get a new item, save its address */ + sm_element_alloc(element); + test = element; + sorted_insert(sm_element, pcol->first_row, pcol->last_row, pcol->length, + next_row, prev_row, row_num, row, test); + + /* if item was not used, free it */ + if (element != test) { + sm_element_free(element); + } + + /* either way, return the current new value */ + return test; +} + + +/* + * remove an element from a col vector + */ +void +sm_col_remove(pcol, row) +register sm_col *pcol; +register int row; +{ + register sm_element *p; + + for(p = pcol->first_row; p != 0 && p->row_num < row; p = p->next_row) + ; + if (p != 0 && p->row_num == row) { + dll_unlink(p, pcol->first_row, pcol->last_row, + next_row, prev_row, pcol->length); + sm_element_free(p); + } +} + + +/* + * find an element (if it is in the col vector) + */ +sm_element * +sm_col_find(pcol, row) +sm_col *pcol; +int row; +{ + register sm_element *p; + + for(p = pcol->first_row; p != 0 && p->row_num < row; p = p->next_row) + ; + if (p != 0 && p->row_num == row) { + return p; + } else { + return NIL(sm_element); + } +} + +/* + * return 1 if col p2 contains col p1; 0 otherwise + */ +int +sm_col_contains(p1, p2) +sm_col *p1, *p2; +{ + register sm_element *q1, *q2; + + q1 = p1->first_row; + q2 = p2->first_row; + while (q1 != 0) { + if (q2 == 0 || q1->row_num < q2->row_num) { + return 0; + } else if (q1->row_num == q2->row_num) { + q1 = q1->next_row; + q2 = q2->next_row; + } else { + q2 = q2->next_row; + } + } + return 1; +} + + +/* + * return 1 if col p1 and col p2 share an element in common + */ +int +sm_col_intersects(p1, p2) +sm_col *p1, *p2; +{ + register sm_element *q1, *q2; + + q1 = p1->first_row; + q2 = p2->first_row; + if (q1 == 0 || q2 == 0) return 0; + for(;;) { + if (q1->row_num < q2->row_num) { + if ((q1 = q1->next_row) == 0) { + return 0; + } + } else if (q1->row_num > q2->row_num) { + if ((q2 = q2->next_row) == 0) { + return 0; + } + } else { + return 1; + } + } +} + + +/* + * compare two cols, lexical ordering + */ +int +sm_col_compare(p1, p2) +sm_col *p1, *p2; +{ + register sm_element *q1, *q2; + + q1 = p1->first_row; + q2 = p2->first_row; + while(q1 != 0 && q2 != 0) { + if (q1->row_num != q2->row_num) { + return q1->row_num - q2->row_num; + } + q1 = q1->next_row; + q2 = q2->next_row; + } + + if (q1 != 0) { + return 1; + } else if (q2 != 0) { + return -1; + } else { + return 0; + } +} + + +/* + * return the intersection + */ +sm_col * +sm_col_and(p1, p2) +sm_col *p1, *p2; +{ + register sm_element *q1, *q2; + register sm_col *result; + + result = sm_col_alloc(); + q1 = p1->first_row; + q2 = p2->first_row; + if (q1 == 0 || q2 == 0) return result; + for(;;) { + if (q1->row_num < q2->row_num) { + if ((q1 = q1->next_row) == 0) { + return result; + } + } else if (q1->row_num > q2->row_num) { + if ((q2 = q2->next_row) == 0) { + return result; + } + } else { + (void) sm_col_insert(result, q1->row_num); + if ((q1 = q1->next_row) == 0) { + return result; + } + if ((q2 = q2->next_row) == 0) { + return result; + } + } + } +} + +int +sm_col_hash(pcol, modulus) +sm_col *pcol; +int modulus; +{ + register int sum; + register sm_element *p; + + sum = 0; + for(p = pcol->first_row; p != 0; p = p->next_row) { + sum = (sum*17 + p->row_num) % modulus; + } + return sum; +} + +/* + * remove an element from a col vector (given a pointer to the element) + */ +void +sm_col_remove_element(pcol, p) +register sm_col *pcol; +register sm_element *p; +{ + dll_unlink(p, pcol->first_row, pcol->last_row, + next_row, prev_row, pcol->length); + sm_element_free(p); +} + + +void +sm_col_print(fp, pcol) +FILE *fp; +sm_col *pcol; +{ + sm_element *p; + + for(p = pcol->first_row; p != 0; p = p->next_row) { + (void) fprintf(fp, " %d", p->row_num); + } +} diff --git a/src/misc/espresso/compl.c b/src/misc/espresso/compl.c new file mode 100644 index 00000000..8f1c6606 --- /dev/null +++ b/src/misc/espresso/compl.c @@ -0,0 +1,680 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +/* + * module: compl.c + * purpose: compute the complement of a multiple-valued function + * + * The "unate recursive paradigm" is used. After a set of special + * cases are examined, the function is split on the "most active + * variable". These two halves are complemented recursively, and then + * the results are merged. + * + * Changes (from Version 2.1 to Version 2.2) + * 1. Minor bug in compl_lifting -- cubes in the left half were + * not marked as active, so that when merging a leaf from the left + * hand side, the active flags were essentially random. This led + * to minor impredictability problem, but never affected the + * accuracy of the results. + */ + +#include "espresso.h" + +#define USE_COMPL_LIFT 0 +#define USE_COMPL_LIFT_ONSET 1 +#define USE_COMPL_LIFT_ONSET_COMPLEX 2 +#define NO_LIFTING 3 + +static bool compl_special_cases(); +static pcover compl_merge(); +static void compl_d1merge(); +static pcover compl_cube(); +static void compl_lift(); +static void compl_lift_onset(); +static void compl_lift_onset_complex(); +static bool simp_comp_special_cases(); +static bool simplify_special_cases(); + + +/* complement -- compute the complement of T */ +pcover complement(T) +pcube *T; /* T will be disposed of */ +{ + register pcube cl, cr; + register int best; + pcover Tbar, Tl, Tr; + int lifting; + static int compl_level = 0; + + if (debug & COMPL) + debug_print(T, "COMPLEMENT", compl_level++); + + if (compl_special_cases(T, &Tbar) == MAYBE) { + + /* Allocate space for the partition cubes */ + cl = new_cube(); + cr = new_cube(); + best = binate_split_select(T, cl, cr, COMPL); + + /* Complement the left and right halves */ + Tl = complement(scofactor(T, cl, best)); + Tr = complement(scofactor(T, cr, best)); + + if (Tr->count*Tl->count > (Tr->count+Tl->count)*CUBELISTSIZE(T)) { + lifting = USE_COMPL_LIFT_ONSET; + } else { + lifting = USE_COMPL_LIFT; + } + Tbar = compl_merge(T, Tl, Tr, cl, cr, best, lifting); + + free_cube(cl); + free_cube(cr); + free_cubelist(T); + } + + if (debug & COMPL) + debug1_print(Tbar, "exit COMPLEMENT", --compl_level); + return Tbar; +} + +static bool compl_special_cases(T, Tbar) +pcube *T; /* will be disposed if answer is determined */ +pcover *Tbar; /* returned only if answer determined */ +{ + register pcube *T1, p, ceil, cof=T[0]; + pcover A, ceil_compl; + + /* Check for no cubes in the cover */ + if (T[2] == NULL) { + *Tbar = sf_addset(new_cover(1), cube.fullset); + free_cubelist(T); + return TRUE; + } + + /* Check for only a single cube in the cover */ + if (T[3] == NULL) { + *Tbar = compl_cube(set_or(cof, cof, T[2])); + free_cubelist(T); + return TRUE; + } + + /* Check for a row of all 1's (implies complement is null) */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (full_row(p, cof)) { + *Tbar = new_cover(0); + free_cubelist(T); + return TRUE; + } + } + + /* Check for a column of all 0's which can be factored out */ + ceil = set_save(cof); + for(T1 = T+2; (p = *T1++) != NULL; ) { + INLINEset_or(ceil, ceil, p); + } + if (! setp_equal(ceil, cube.fullset)) { + ceil_compl = compl_cube(ceil); + (void) set_or(cof, cof, set_diff(ceil, cube.fullset, ceil)); + set_free(ceil); + *Tbar = sf_append(complement(T), ceil_compl); + return TRUE; + } + set_free(ceil); + + /* Collect column counts, determine unate variables, etc. */ + massive_count(T); + + /* If single active variable not factored out above, then tautology ! */ + if (cdata.vars_active == 1) { + *Tbar = new_cover(0); + free_cubelist(T); + return TRUE; + + /* Check for unate cover */ + } else if (cdata.vars_unate == cdata.vars_active) { + A = map_cover_to_unate(T); + free_cubelist(T); + A = unate_compl(A); + *Tbar = map_unate_to_cover(A); + sf_free(A); + return TRUE; + + /* Not much we can do about it */ + } else { + return MAYBE; + } +} + +/* + * compl_merge -- merge the two cofactors around the splitting + * variable + * + * The merge operation involves intersecting each cube of the left + * cofactor with cl, and intersecting each cube of the right cofactor + * with cr. The union of these two covers is the merged result. + * + * In order to reduce the number of cubes, a distance-1 merge is + * performed (note that two cubes can only combine distance-1 in the + * splitting variable). Also, a simple expand is performed in the + * splitting variable (simple implies the covering check for the + * expansion is not full containment, but single-cube containment). + */ + +static pcover compl_merge(T1, L, R, cl, cr, var, lifting) +pcube *T1; /* Original ON-set */ +pcover L, R; /* Complement from each recursion branch */ +register pcube cl, cr; /* cubes used for cofactoring */ +int var; /* splitting variable */ +int lifting; /* whether to perform lifting or not */ +{ + register pcube p, last, pt; + pcover T, Tbar; + pcube *L1, *R1; + + if (debug & COMPL) { + (void) printf("compl_merge: left %d, right %d\n", L->count, R->count); + (void) printf("%s (cl)\n%s (cr)\nLeft is\n", pc1(cl), pc2(cr)); + cprint(L); + (void) printf("Right is\n"); + cprint(R); + } + + /* Intersect each cube with the cofactored cube */ + foreach_set(L, last, p) { + INLINEset_and(p, p, cl); + SET(p, ACTIVE); + } + foreach_set(R, last, p) { + INLINEset_and(p, p, cr); + SET(p, ACTIVE); + } + + /* Sort the arrays for a distance-1 merge */ + (void) set_copy(cube.temp[0], cube.var_mask[var]); + qsort((char *) (L1 = sf_list(L)), L->count, sizeof(pset), (int (*)()) d1_order); + qsort((char *) (R1 = sf_list(R)), R->count, sizeof(pset), (int (*)()) d1_order); + + /* Perform distance-1 merge */ + compl_d1merge(L1, R1); + + /* Perform lifting */ + switch(lifting) { + case USE_COMPL_LIFT_ONSET: + T = cubeunlist(T1); + compl_lift_onset(L1, T, cr, var); + compl_lift_onset(R1, T, cl, var); + free_cover(T); + break; + case USE_COMPL_LIFT_ONSET_COMPLEX: + T = cubeunlist(T1); + compl_lift_onset_complex(L1, T, var); + compl_lift_onset_complex(R1, T, var); + free_cover(T); + break; + case USE_COMPL_LIFT: + compl_lift(L1, R1, cr, var); + compl_lift(R1, L1, cl, var); + break; + case NO_LIFTING: + break; + default: + ; + } + FREE(L1); + FREE(R1); + + /* Re-create the merged cover */ + Tbar = new_cover(L->count + R->count); + pt = Tbar->data; + foreach_set(L, last, p) { + INLINEset_copy(pt, p); + Tbar->count++; + pt += Tbar->wsize; + } + foreach_active_set(R, last, p) { + INLINEset_copy(pt, p); + Tbar->count++; + pt += Tbar->wsize; + } + + if (debug & COMPL) { + (void) printf("Result %d\n", Tbar->count); + if (verbose_debug) + cprint(Tbar); + } + + free_cover(L); + free_cover(R); + return Tbar; +} + +/* + * compl_lift_simple -- expand in the splitting variable using single + * cube containment against the other recursion branch to check + * validity of the expansion, and expanding all (or none) of the + * splitting variable. + */ +static void compl_lift(A1, B1, bcube, var) +pcube *A1, *B1, bcube; +int var; +{ + register pcube a, b, *B2, lift=cube.temp[4], liftor=cube.temp[5]; + pcube mask = cube.var_mask[var]; + + (void) set_and(liftor, bcube, mask); + + /* for each cube in the first array ... */ + for(; (a = *A1++) != NULL; ) { + if (TESTP(a, ACTIVE)) { + + /* create a lift of this cube in the merging coord */ + (void) set_merge(lift, bcube, a, mask); + + /* for each cube in the second array */ + for(B2 = B1; (b = *B2++) != NULL; ) { + INLINEsetp_implies(lift, b, /* when_false => */ continue); + /* when_true => fall through to next statement */ + + /* cube of A1 was contained by some cube of B1, so raise */ + INLINEset_or(a, a, liftor); + break; + } + } + } +} + + + +/* + * compl_lift_onset -- expand in the splitting variable using a + * distance-1 check against the original on-set; expand all (or + * none) of the splitting variable. Each cube of A1 is expanded + * against the original on-set T. + */ +static void compl_lift_onset(A1, T, bcube, var) +pcube *A1; +pcover T; +pcube bcube; +int var; +{ + register pcube a, last, p, lift=cube.temp[4], mask=cube.var_mask[var]; + + /* for each active cube from one branch of the complement */ + for(; (a = *A1++) != NULL; ) { + if (TESTP(a, ACTIVE)) { + + /* create a lift of this cube in the merging coord */ + INLINEset_and(lift, bcube, mask); /* isolate parts to raise */ + INLINEset_or(lift, a, lift); /* raise these parts in a */ + + /* for each cube in the ON-set, check for intersection */ + foreach_set(T, last, p) { + if (cdist0(p, lift)) { + goto nolift; + } + } + INLINEset_copy(a, lift); /* save the raising */ + SET(a, ACTIVE); +nolift : ; + } + } +} + +/* + * compl_lift_complex -- expand in the splitting variable, but expand all + * parts which can possibly expand. + * T is the original ON-set + * A1 is either the left or right cofactor + */ +static void compl_lift_onset_complex(A1, T, var) +pcube *A1; /* array of pointers to new result */ +pcover T; /* original ON-set */ +int var; /* which variable we split on */ +{ + register int dist; + register pcube last, p, a, xlower; + + /* for each cube in the complement */ + xlower = new_cube(); + for(; (a = *A1++) != NULL; ) { + + if (TESTP(a, ACTIVE)) { + + /* Find which parts of the splitting variable are forced low */ + INLINEset_clear(xlower, cube.size); + foreach_set(T, last, p) { + if ((dist = cdist01(p, a)) < 2) { + if (dist == 0) { + fatal("compl: ON-set and OFF-set are not orthogonal"); + } else { + (void) force_lower(xlower, p, a); + } + } + } + + (void) set_diff(xlower, cube.var_mask[var], xlower); + (void) set_or(a, a, xlower); + free_cube(xlower); + } + } +} + + + +/* + * compl_d1merge -- distance-1 merge in the splitting variable + */ +static void compl_d1merge(L1, R1) +register pcube *L1, *R1; +{ + register pcube pl, pr; + + /* Find equal cubes between the two cofactors */ + for(pl = *L1, pr = *R1; (pl != NULL) && (pr != NULL); ) + switch (d1_order(L1, R1)) { + case 1: + pr = *(++R1); break; /* advance right pointer */ + case -1: + pl = *(++L1); break; /* advance left pointer */ + case 0: + RESET(pr, ACTIVE); + INLINEset_or(pl, pl, pr); + pr = *(++R1); + default: + ; + } +} + + + +/* compl_cube -- return the complement of a single cube (De Morgan's law) */ +static pcover compl_cube(p) +register pcube p; +{ + register pcube diff=cube.temp[7], pdest, mask, full=cube.fullset; + int var; + pcover R; + + /* Allocate worst-case size cover (to avoid checking overflow) */ + R = new_cover(cube.num_vars); + + /* Compute bit-wise complement of the cube */ + INLINEset_diff(diff, full, p); + + for(var = 0; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; + /* If the bit-wise complement is not empty in var ... */ + if (! setp_disjoint(diff, mask)) { + pdest = GETSET(R, R->count++); + INLINEset_merge(pdest, diff, full, mask); + } + } + return R; +} + +/* simp_comp -- quick simplification of T */ +void simp_comp(T, Tnew, Tbar) +pcube *T; /* T will be disposed of */ +pcover *Tnew; +pcover *Tbar; +{ + register pcube cl, cr; + register int best; + pcover Tl, Tr, Tlbar, Trbar; + int lifting; + static int simplify_level = 0; + + if (debug & COMPL) + debug_print(T, "SIMPCOMP", simplify_level++); + + if (simp_comp_special_cases(T, Tnew, Tbar) == MAYBE) { + + /* Allocate space for the partition cubes */ + cl = new_cube(); + cr = new_cube(); + best = binate_split_select(T, cl, cr, COMPL); + + /* Complement the left and right halves */ + simp_comp(scofactor(T, cl, best), &Tl, &Tlbar); + simp_comp(scofactor(T, cr, best), &Tr, &Trbar); + + lifting = USE_COMPL_LIFT; + *Tnew = compl_merge(T, Tl, Tr, cl, cr, best, lifting); + + lifting = USE_COMPL_LIFT; + *Tbar = compl_merge(T, Tlbar, Trbar, cl, cr, best, lifting); + + /* All of this work for nothing ? Let's hope not ... */ + if ((*Tnew)->count > CUBELISTSIZE(T)) { + sf_free(*Tnew); + *Tnew = cubeunlist(T); + } + + free_cube(cl); + free_cube(cr); + free_cubelist(T); + } + + if (debug & COMPL) { + debug1_print(*Tnew, "exit SIMPCOMP (new)", simplify_level); + debug1_print(*Tbar, "exit SIMPCOMP (compl)", simplify_level); + simplify_level--; + } +} + +static bool simp_comp_special_cases(T, Tnew, Tbar) +pcube *T; /* will be disposed if answer is determined */ +pcover *Tnew; /* returned only if answer determined */ +pcover *Tbar; /* returned only if answer determined */ +{ + register pcube *T1, p, ceil, cof=T[0]; + pcube last; + pcover A; + + /* Check for no cubes in the cover (function is empty) */ + if (T[2] == NULL) { + *Tnew = new_cover(1); + *Tbar = sf_addset(new_cover(1), cube.fullset); + free_cubelist(T); + return TRUE; + } + + /* Check for only a single cube in the cover */ + if (T[3] == NULL) { + (void) set_or(cof, cof, T[2]); + *Tnew = sf_addset(new_cover(1), cof); + *Tbar = compl_cube(cof); + free_cubelist(T); + return TRUE; + } + + /* Check for a row of all 1's (function is a tautology) */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (full_row(p, cof)) { + *Tnew = sf_addset(new_cover(1), cube.fullset); + *Tbar = new_cover(1); + free_cubelist(T); + return TRUE; + } + } + + /* Check for a column of all 0's which can be factored out */ + ceil = set_save(cof); + for(T1 = T+2; (p = *T1++) != NULL; ) { + INLINEset_or(ceil, ceil, p); + } + if (! setp_equal(ceil, cube.fullset)) { + p = new_cube(); + (void) set_diff(p, cube.fullset, ceil); + (void) set_or(cof, cof, p); + set_free(p); + simp_comp(T, Tnew, Tbar); + + /* Adjust the ON-set */ + A = *Tnew; + foreach_set(A, last, p) { + INLINEset_and(p, p, ceil); + } + + /* Compute the new complement */ + *Tbar = sf_append(*Tbar, compl_cube(ceil)); + set_free(ceil); + return TRUE; + } + set_free(ceil); + + /* Collect column counts, determine unate variables, etc. */ + massive_count(T); + + /* If single active variable not factored out above, then tautology ! */ + if (cdata.vars_active == 1) { + *Tnew = sf_addset(new_cover(1), cube.fullset); + *Tbar = new_cover(1); + free_cubelist(T); + return TRUE; + + /* Check for unate cover */ + } else if (cdata.vars_unate == cdata.vars_active) { + /* Make the cover minimum by single-cube containment */ + A = cubeunlist(T); + *Tnew = sf_contain(A); + + /* Now form a minimum representation of the complement */ + A = map_cover_to_unate(T); + A = unate_compl(A); + *Tbar = map_unate_to_cover(A); + sf_free(A); + free_cubelist(T); + return TRUE; + + /* Not much we can do about it */ + } else { + return MAYBE; + } +} + +/* simplify -- quick simplification of T */ +pcover simplify(T) +pcube *T; /* T will be disposed of */ +{ + register pcube cl, cr; + register int best; + pcover Tbar, Tl, Tr; + int lifting; + static int simplify_level = 0; + + if (debug & COMPL) { + debug_print(T, "SIMPLIFY", simplify_level++); + } + + if (simplify_special_cases(T, &Tbar) == MAYBE) { + + /* Allocate space for the partition cubes */ + cl = new_cube(); + cr = new_cube(); + + best = binate_split_select(T, cl, cr, COMPL); + + /* Complement the left and right halves */ + Tl = simplify(scofactor(T, cl, best)); + Tr = simplify(scofactor(T, cr, best)); + + lifting = USE_COMPL_LIFT; + Tbar = compl_merge(T, Tl, Tr, cl, cr, best, lifting); + + /* All of this work for nothing ? Let's hope not ... */ + if (Tbar->count > CUBELISTSIZE(T)) { + sf_free(Tbar); + Tbar = cubeunlist(T); + } + + free_cube(cl); + free_cube(cr); + free_cubelist(T); + } + + if (debug & COMPL) { + debug1_print(Tbar, "exit SIMPLIFY", --simplify_level); + } + return Tbar; +} + +static bool simplify_special_cases(T, Tnew) +pcube *T; /* will be disposed if answer is determined */ +pcover *Tnew; /* returned only if answer determined */ +{ + register pcube *T1, p, ceil, cof=T[0]; + pcube last; + pcover A; + + /* Check for no cubes in the cover */ + if (T[2] == NULL) { + *Tnew = new_cover(0); + free_cubelist(T); + return TRUE; + } + + /* Check for only a single cube in the cover */ + if (T[3] == NULL) { + *Tnew = sf_addset(new_cover(1), set_or(cof, cof, T[2])); + free_cubelist(T); + return TRUE; + } + + /* Check for a row of all 1's (implies function is a tautology) */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (full_row(p, cof)) { + *Tnew = sf_addset(new_cover(1), cube.fullset); + free_cubelist(T); + return TRUE; + } + } + + /* Check for a column of all 0's which can be factored out */ + ceil = set_save(cof); + for(T1 = T+2; (p = *T1++) != NULL; ) { + INLINEset_or(ceil, ceil, p); + } + if (! setp_equal(ceil, cube.fullset)) { + p = new_cube(); + (void) set_diff(p, cube.fullset, ceil); + (void) set_or(cof, cof, p); + free_cube(p); + + A = simplify(T); + foreach_set(A, last, p) { + INLINEset_and(p, p, ceil); + } + *Tnew = A; + set_free(ceil); + return TRUE; + } + set_free(ceil); + + /* Collect column counts, determine unate variables, etc. */ + massive_count(T); + + /* If single active variable not factored out above, then tautology ! */ + if (cdata.vars_active == 1) { + *Tnew = sf_addset(new_cover(1), cube.fullset); + free_cubelist(T); + return TRUE; + + /* Check for unate cover */ + } else if (cdata.vars_unate == cdata.vars_active) { + A = cubeunlist(T); + *Tnew = sf_contain(A); + free_cubelist(T); + return TRUE; + + /* Not much we can do about it */ + } else { + return MAYBE; + } +} diff --git a/src/misc/espresso/contain.c b/src/misc/espresso/contain.c new file mode 100644 index 00000000..180dceb6 --- /dev/null +++ b/src/misc/espresso/contain.c @@ -0,0 +1,441 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +/* + contain.c -- set containment routines + + These are complex routines for performing containment over a + family of sets, but they have the advantage of being much faster + than a straightforward n*n routine. + + First the cubes are sorted by size, and as a secondary key they are + sorted so that if two cubes are equal they end up adjacent. We can + than quickly remove equal cubes from further consideration by + comparing each cube to its neighbor. Finally, because the cubes + are sorted by size, we need only check cubes which are larger (or + smaller) than a given cube for containment. +*/ + +#include "espresso.h" + + +/* + sf_contain -- perform containment on a set family (delete sets which + are contained by some larger set in the family). No assumptions are + made about A, and the result will be returned in decreasing order of + set size. +*/ +pset_family sf_contain(A) +INOUT pset_family A; /* disposes of A */ +{ + int cnt; + pset *A1; + pset_family R; + + A1 = sf_sort(A, descend); /* sort into descending order */ + cnt = rm_equal(A1, descend); /* remove duplicates */ + cnt = rm_contain(A1); /* remove contained sets */ + R = sf_unlist(A1, cnt, A->sf_size); /* recreate the set family */ + sf_free(A); + return R; +} + + +/* + sf_rev_contain -- perform containment on a set family (delete sets which + contain some smaller set in the family). No assumptions are made about + A, and the result will be returned in increasing order of set size +*/ +pset_family sf_rev_contain(A) +INOUT pset_family A; /* disposes of A */ +{ + int cnt; + pset *A1; + pset_family R; + + A1 = sf_sort(A, ascend); /* sort into ascending order */ + cnt = rm_equal(A1, ascend); /* remove duplicates */ + cnt = rm_rev_contain(A1); /* remove containing sets */ + R = sf_unlist(A1, cnt, A->sf_size); /* recreate the set family */ + sf_free(A); + return R; +} + + +/* + sf_ind_contain -- perform containment on a set family (delete sets which + are contained by some larger set in the family). No assumptions are + made about A, and the result will be returned in decreasing order of + set size. Also maintains a set of row_indices to track which rows + disappear and how the rows end up permuted. +*/ +pset_family sf_ind_contain(A, row_indices) +INOUT pset_family A; /* disposes of A */ +INOUT int *row_indices; /* updated with the new values */ +{ + int cnt; + pset *A1; + pset_family R; + + A1 = sf_sort(A, descend); /* sort into descending order */ + cnt = rm_equal(A1, descend); /* remove duplicates */ + cnt = rm_contain(A1); /* remove contained sets */ + R = sf_ind_unlist(A1, cnt, A->sf_size, row_indices, A->data); + sf_free(A); + return R; +} + + +/* sf_dupl -- delete duplicate sets in a set family */ +pset_family sf_dupl(A) +INOUT pset_family A; /* disposes of A */ +{ + register int cnt; + register pset *A1; + pset_family R; + + A1 = sf_sort(A, descend); /* sort the set family */ + cnt = rm_equal(A1, descend); /* remove duplicates */ + R = sf_unlist(A1, cnt, A->sf_size); /* recreate the set family */ + sf_free(A); + return R; +} + + +/* + sf_union -- form the contained union of two set families (delete + sets which are contained by some larger set in the family). A and + B are assumed already sorted in decreasing order of set size (and + the SIZE field is assumed to contain the set size), and the result + will be returned sorted likewise. +*/ +pset_family sf_union(A, B) +INOUT pset_family A, B; /* disposes of A and B */ +{ + int cnt; + pset_family R; + pset *A1 = sf_list(A), *B1 = sf_list(B), *E1; + + E1 = ALLOC(pset, MAX(A->count, B->count) + 1); + cnt = rm2_equal(A1, B1, E1, descend); + cnt += rm2_contain(A1, B1) + rm2_contain(B1, A1); + R = sf_merge(A1, B1, E1, cnt, A->sf_size); + sf_free(A); sf_free(B); + return R; +} + + +/* + dist_merge -- consider all sets to be "or"-ed with "mask" and then + delete duplicates from the set family. +*/ +pset_family dist_merge(A, mask) +INOUT pset_family A; /* disposes of A */ +IN pset mask; /* defines variables to mask out */ +{ + pset *A1; + int cnt; + pset_family R; + + (void) set_copy(cube.temp[0], mask); + A1 = sf_sort(A, d1_order); + cnt = d1_rm_equal(A1, d1_order); + R = sf_unlist(A1, cnt, A->sf_size); + sf_free(A); + return R; +} + + +/* + d1merge -- perform an efficient distance-1 merge of cubes of A +*/ +pset_family d1merge(A, var) +INOUT pset_family A; /* disposes of A */ +IN int var; +{ + return dist_merge(A, cube.var_mask[var]); +} + + + +/* d1_rm_equal -- distance-1 merge (merge cubes which are equal under a mask) */ +int d1_rm_equal(A1, compare) +register pset *A1; /* array of set pointers */ +int (*compare)(); /* comparison function */ +{ + register int i, j, dest; + + dest = 0; + if (A1[0] != (pcube) NULL) { + for(i = 0, j = 1; A1[j] != (pcube) NULL; j++) + if ( (*compare)(&A1[i], &A1[j]) == 0) { + /* if sets are equal (under the mask) merge them */ + (void) set_or(A1[i], A1[i], A1[j]); + } else { + /* sets are unequal, so save the set i */ + A1[dest++] = A1[i]; + i = j; + } + A1[dest++] = A1[i]; + } + A1[dest] = (pcube) NULL; + return dest; +} + + +/* rm_equal -- scan a sorted array of set pointers for duplicate sets */ +int rm_equal(A1, compare) +INOUT pset *A1; /* updated in place */ +IN int (*compare)(); +{ + register pset *p, *pdest = A1; + + if (*A1 != NULL) { /* If more than one set */ + for(p = A1+1; *p != NULL; p++) + if ((*compare)(p, p-1) != 0) + *pdest++ = *(p-1); + *pdest++ = *(p-1); + *pdest = NULL; + } + return pdest - A1; +} + + +/* rm_contain -- perform containment over a sorted array of set pointers */ +int rm_contain(A1) +INOUT pset *A1; /* updated in place */ +{ + register pset *pa, *pb, *pcheck, a, b; + pset *pdest = A1; + int last_size = -1; + + /* Loop for all cubes of A1 */ + for(pa = A1; (a = *pa++) != NULL; ) { + /* Update the check pointer if the size has changed */ + if (SIZE(a) != last_size) + last_size = SIZE(a), pcheck = pdest; + for(pb = A1; pb != pcheck; ) { + b = *pb++; + INLINEsetp_implies(a, b, /* when_false => */ continue); + goto lnext1; + } + /* set a was not contained by some larger set, so save it */ + *pdest++ = a; + lnext1: ; + } + + *pdest = NULL; + return pdest - A1; +} + + +/* rm_rev_contain -- perform rcontainment over a sorted array of set pointers */ +int rm_rev_contain(A1) +INOUT pset *A1; /* updated in place */ +{ + register pset *pa, *pb, *pcheck, a, b; + pset *pdest = A1; + int last_size = -1; + + /* Loop for all cubes of A1 */ + for(pa = A1; (a = *pa++) != NULL; ) { + /* Update the check pointer if the size has changed */ + if (SIZE(a) != last_size) + last_size = SIZE(a), pcheck = pdest; + for(pb = A1; pb != pcheck; ) { + b = *pb++; + INLINEsetp_implies(b, a, /* when_false => */ continue); + goto lnext1; + } + /* the set a did not contain some smaller set, so save it */ + *pdest++ = a; + lnext1: ; + } + + *pdest = NULL; + return pdest - A1; +} + + +/* rm2_equal -- check two sorted arrays of set pointers for equal cubes */ +int rm2_equal(A1, B1, E1, compare) +INOUT register pset *A1, *B1; /* updated in place */ +OUT pset *E1; +IN int (*compare)(); +{ + register pset *pda = A1, *pdb = B1, *pde = E1; + + /* Walk through the arrays advancing pointer to larger cube */ + for(; *A1 != NULL && *B1 != NULL; ) + switch((*compare)(A1, B1)) { + case -1: /* "a" comes before "b" */ + *pda++ = *A1++; break; + case 0: /* equal cubes */ + *pde++ = *A1++; B1++; break; + case 1: /* "a" is to follow "b" */ + *pdb++ = *B1++; break; + } + + /* Finish moving down the pointers of A and B */ + while (*A1 != NULL) + *pda++ = *A1++; + while (*B1 != NULL) + *pdb++ = *B1++; + *pda = *pdb = *pde = NULL; + + return pde - E1; +} + + +/* rm2_contain -- perform containment between two arrays of set pointers */ +int rm2_contain(A1, B1) +INOUT pset *A1; /* updated in place */ +IN pset *B1; /* unchanged */ +{ + register pset *pa, *pb, a, b, *pdest = A1; + + /* for each set in the first array ... */ + for(pa = A1; (a = *pa++) != NULL; ) { + /* for each set in the second array which is larger ... */ + for(pb = B1; (b = *pb++) != NULL && SIZE(b) > SIZE(a); ) { + INLINEsetp_implies(a, b, /* when_false => */ continue); + /* set was contained in some set of B, so don't save pointer */ + goto lnext1; + } + /* set wasn't contained in any set of B, so save the pointer */ + *pdest++ = a; + lnext1: ; + } + + *pdest = NULL; /* sentinel */ + return pdest - A1; /* # elements in A1 */ +} + + + +/* sf_sort -- sort the sets of A */ +pset *sf_sort(A, compare) +IN pset_family A; +IN int (*compare)(); +{ + register pset p, last, *pdest, *A1; + + /* Create a single array pointing to each cube of A */ + pdest = A1 = ALLOC(pset, A->count + 1); + foreach_set(A, last, p) { + PUTSIZE(p, set_ord(p)); /* compute the set size */ + *pdest++ = p; /* save the pointer */ + } + *pdest = NULL; /* Sentinel -- never seen by sort */ + + /* Sort cubes by size */ + qsort((char *) A1, A->count, sizeof(pset), compare); + return A1; +} + + +/* sf_list -- make a list of pointers to the sets in a set family */ +pset *sf_list(A) +IN register pset_family A; +{ + register pset p, last, *pdest, *A1; + + /* Create a single array pointing to each cube of A */ + pdest = A1 = ALLOC(pset, A->count + 1); + foreach_set(A, last, p) + *pdest++ = p; /* save the pointer */ + *pdest = NULL; /* Sentinel */ + return A1; +} + + +/* sf_unlist -- make a set family out of a list of pointers to sets */ +pset_family sf_unlist(A1, totcnt, size) +IN pset *A1; +IN int totcnt, size; +{ + register pset pr, p, *pa; + pset_family R = sf_new(totcnt, size); + + R->count = totcnt; + for(pr = R->data, pa = A1; (p = *pa++) != NULL; pr += R->wsize) + INLINEset_copy(pr, p); + FREE(A1); + return R; +} + + +/* sf_ind_unlist -- make a set family out of a list of pointers to sets */ +pset_family sf_ind_unlist(A1, totcnt, size, row_indices, pfirst) +IN pset *A1; +IN int totcnt, size; +INOUT int *row_indices; +IN register pset pfirst; +{ + register pset pr, p, *pa; + register int i, *new_row_indices; + pset_family R = sf_new(totcnt, size); + + R->count = totcnt; + new_row_indices = ALLOC(int, totcnt); + for(pr = R->data, pa = A1, i=0; (p = *pa++) != NULL; pr += R->wsize, i++) { + INLINEset_copy(pr, p); + new_row_indices[i] = row_indices[(p - pfirst)/R->wsize]; + } + for(i = 0; i < totcnt; i++) + row_indices[i] = new_row_indices[i]; + FREE(new_row_indices); + FREE(A1); + return R; +} + + +/* sf_merge -- merge three sorted lists of set pointers */ +pset_family sf_merge(A1, B1, E1, totcnt, size) +INOUT pset *A1, *B1, *E1; /* will be disposed of */ +IN int totcnt, size; +{ + register pset pr, ps, *pmin, *pmid, *pmax; + pset_family R; + pset *temp[3], *swap; + int i, j, n; + + /* Allocate the result set_family */ + R = sf_new(totcnt, size); + R->count = totcnt; + pr = R->data; + + /* Quick bubble sort to order the top member of the three arrays */ + n = 3; temp[0] = A1; temp[1] = B1; temp[2] = E1; + for(i = 0; i < n-1; i++) + for(j = i+1; j < n; j++) + if (desc1(*temp[i], *temp[j]) > 0) { + swap = temp[j]; + temp[j] = temp[i]; + temp[i] = swap; + } + pmin = temp[0]; pmid = temp[1]; pmax = temp[2]; + + /* Save the minimum element, then update pmin, pmid, pmax */ + while (*pmin != (pset) NULL) { + ps = *pmin++; + INLINEset_copy(pr, ps); + pr += R->wsize; + if (desc1(*pmin, *pmax) > 0) { + swap = pmax; pmax = pmin; pmin = pmid; pmid = swap; + } else if (desc1(*pmin, *pmid) > 0) { + swap = pmin; pmin = pmid; pmid = swap; + } + } + + FREE(A1); + FREE(B1); + FREE(E1); + return R; +} diff --git a/src/misc/espresso/cubehack.c b/src/misc/espresso/cubehack.c new file mode 100644 index 00000000..8e1724fc --- /dev/null +++ b/src/misc/espresso/cubehack.c @@ -0,0 +1,138 @@ +/* + * Revision Control Information + * + * $Source: /vol/opua/opua2/sis/sis-1.1/common/src/sis/node/RCS/cubehack.c,v $ + * $Author: sis $ + * $Revision: 1.2 $ + * $Date: 1992/05/06 18:57:41 $ + * + */ +/* +#include "sis.h" +#include "node_int.h" + +#ifdef lint +struct cube_struct cube; +bool summary; +bool trace; +bool remove_essential; +bool force_irredundant; +bool unwrap_onset; +bool single_expand; +bool pos; +bool recompute_onset; +bool use_super_gasp; +bool use_random_order; +#endif +*/ +#include "espresso.h" + + +void +cautious_define_cube_size(n) +int n; +{ + if (cube.fullset != 0 && cube.num_binary_vars == n) + return; + if (cube.fullset != 0) { + setdown_cube(); + FREE(cube.part_size); + } + cube.num_binary_vars = cube.num_vars = n; + cube.part_size = ALLOC(int, n); + cube_setup(); +} + + +void +define_cube_size(n) +int n; +{ + register int q, i; + static int called_before = 0; + + /* check if the cube is already just the right size */ + if (cube.fullset != 0 && cube.num_binary_vars == n && cube.num_vars == n) + return; + + /* We can't handle more than 100 inputs */ + if (n > 100) { + cautious_define_cube_size(n); + called_before = 0; + return; + } + + if (cube.fullset == 0 || ! called_before) { + cautious_define_cube_size(100); + called_before = 1; + } + + cube.num_vars = n; + cube.num_binary_vars = n; + cube.num_mv_vars = 0; + cube.output = -1; + cube.size = n * 2; + + /* first_part, last_part, first_word, last_word, part_size OKAY */ + /* cube.sparse is OKAY */ + + /* need to completely re-make cube.fullset and cube.binary_mask */ + (void) set_fill(cube.fullset, n*2); + (void) set_fill(cube.binary_mask, n*2); + + /* need to resize each set in cube.var_mask and cube.temp */ + q = cube.fullset[0]; + for(i = 0; i < cube.num_vars; i++) + cube.var_mask[i][0] = q; + for(i = 0; i < CUBE_TEMP; i++) + cube.temp[i][0] = q; + + /* need to resize cube.emptyset and cube.mv_mask */ + cube.emptyset[0] = q; + cube.mv_mask[0] = q; + + /* need to reset the inword and inmask */ + if (cube.num_binary_vars != 0) { + cube.inword = cube.last_word[cube.num_binary_vars - 1]; + cube.inmask = cube.binary_mask[cube.inword] & DISJOINT; + } else { + cube.inword = -1; + cube.inmask = 0; + } + + /* cdata (entire structure) is OKAY */ +} + + +void +undefine_cube_size() +{ + if (cube.num_binary_vars > 100) { + if (cube.fullset != 0) { + setdown_cube(); + FREE(cube.part_size); + } + } else { + cube.num_vars = cube.num_binary_vars = 100; + if (cube.fullset != 0) { + setdown_cube(); + FREE(cube.part_size); + } + } +} + + +void +set_espresso_flags() +{ + summary = FALSE; + trace = FALSE; + remove_essential = TRUE; + force_irredundant = TRUE; + unwrap_onset = TRUE; + single_expand = FALSE; + pos = FALSE; + recompute_onset = FALSE; + use_super_gasp = FALSE; + use_random_order = FALSE; +} diff --git a/src/misc/espresso/cubestr.c b/src/misc/espresso/cubestr.c new file mode 100644 index 00000000..77389e73 --- /dev/null +++ b/src/misc/espresso/cubestr.c @@ -0,0 +1,152 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +/* + Module: cubestr.c -- routines for managing the global cube structure +*/ + +#include "espresso.h" + +/* + cube_setup -- assume that the fields "num_vars", "num_binary_vars", and + part_size[num_binary_vars .. num_vars-1] are setup, and initialize the + rest of cube and cdata. + + If a part_size is < 0, then the field size is abs(part_size) and the + field read from the input is symbolic. +*/ +void cube_setup() +{ + register int i, var; + register pcube p; + + if (cube.num_binary_vars < 0 || cube.num_vars < cube.num_binary_vars) + fatal("cube size is silly, error in .i/.o or .mv"); + + cube.num_mv_vars = cube.num_vars - cube.num_binary_vars; + cube.output = cube.num_mv_vars > 0 ? cube.num_vars - 1 : -1; + + cube.size = 0; + cube.first_part = ALLOC(int, cube.num_vars); + cube.last_part = ALLOC(int, cube.num_vars); + cube.first_word = ALLOC(int, cube.num_vars); + cube.last_word = ALLOC(int, cube.num_vars); + for(var = 0; var < cube.num_vars; var++) { + if (var < cube.num_binary_vars) + cube.part_size[var] = 2; + cube.first_part[var] = cube.size; + cube.first_word[var] = WHICH_WORD(cube.size); + cube.size += ABS(cube.part_size[var]); + cube.last_part[var] = cube.size - 1; + cube.last_word[var] = WHICH_WORD(cube.size - 1); + } + + cube.var_mask = ALLOC(pset, cube.num_vars); + cube.sparse = ALLOC(int, cube.num_vars); + cube.binary_mask = new_cube(); + cube.mv_mask = new_cube(); + for(var = 0; var < cube.num_vars; var++) { + p = cube.var_mask[var] = new_cube(); + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) + set_insert(p, i); + if (var < cube.num_binary_vars) { + INLINEset_or(cube.binary_mask, cube.binary_mask, p); + cube.sparse[var] = 0; + } else { + INLINEset_or(cube.mv_mask, cube.mv_mask, p); + cube.sparse[var] = 1; + } + } + if (cube.num_binary_vars == 0) + cube.inword = -1; + else { + cube.inword = cube.last_word[cube.num_binary_vars - 1]; + cube.inmask = cube.binary_mask[cube.inword] & DISJOINT; + } + + cube.temp = ALLOC(pset, CUBE_TEMP); + for(i = 0; i < CUBE_TEMP; i++) + cube.temp[i] = new_cube(); + cube.fullset = set_fill(new_cube(), cube.size); + cube.emptyset = new_cube(); + + cdata.part_zeros = ALLOC(int, cube.size); + cdata.var_zeros = ALLOC(int, cube.num_vars); + cdata.parts_active = ALLOC(int, cube.num_vars); + cdata.is_unate = ALLOC(int, cube.num_vars); +} + +/* + setdown_cube -- free memory allocated for the cube/cdata structs + (free's all but the part_size array) + + (I wanted to call this cube_setdown, but that violates the 8-character + external routine limit on the IBM !) +*/ +void setdown_cube() +{ + register int i, var; + + FREE(cube.first_part); + FREE(cube.last_part); + FREE(cube.first_word); + FREE(cube.last_word); + FREE(cube.sparse); + + free_cube(cube.binary_mask); + free_cube(cube.mv_mask); + free_cube(cube.fullset); + free_cube(cube.emptyset); + for(var = 0; var < cube.num_vars; var++) + free_cube(cube.var_mask[var]); + FREE(cube.var_mask); + + for(i = 0; i < CUBE_TEMP; i++) + free_cube(cube.temp[i]); + FREE(cube.temp); + + FREE(cdata.part_zeros); + FREE(cdata.var_zeros); + FREE(cdata.parts_active); + FREE(cdata.is_unate); + + cube.first_part = cube.last_part = (int *) NULL; + cube.first_word = cube.last_word = (int *) NULL; + cube.sparse = (int *) NULL; + cube.binary_mask = cube.mv_mask = (pcube) NULL; + cube.fullset = cube.emptyset = (pcube) NULL; + cube.var_mask = cube.temp = (pcube *) NULL; + + cdata.part_zeros = cdata.var_zeros = cdata.parts_active = (int *) NULL; + cdata.is_unate = (bool *) NULL; +} + + +void save_cube_struct() +{ + temp_cube_save = cube; /* structure copy ! */ + temp_cdata_save = cdata; /* "" */ + + cube.first_part = cube.last_part = (int *) NULL; + cube.first_word = cube.last_word = (int *) NULL; + cube.part_size = (int *) NULL; + cube.binary_mask = cube.mv_mask = (pcube) NULL; + cube.fullset = cube.emptyset = (pcube) NULL; + cube.var_mask = cube.temp = (pcube *) NULL; + + cdata.part_zeros = cdata.var_zeros = cdata.parts_active = (int *) NULL; + cdata.is_unate = (bool *) NULL; +} + + +void restore_cube_struct() +{ + cube = temp_cube_save; /* structure copy ! */ + cdata = temp_cdata_save; /* "" */ +} diff --git a/src/misc/espresso/cvrin.c b/src/misc/espresso/cvrin.c new file mode 100644 index 00000000..7790b38b --- /dev/null +++ b/src/misc/espresso/cvrin.c @@ -0,0 +1,810 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +/* + module: cvrin.c + purpose: cube and cover input routines +*/ + +#include "espresso.h" + +static bool line_length_error; +static int lineno; + +void skip_line(fpin, fpout, echo) +register FILE *fpin, *fpout; +register bool echo; +{ + register int ch; + while ((ch=getc(fpin)) != EOF && ch != '\n') + if (echo) + putc(ch, fpout); + if (echo) + putc('\n', fpout); + lineno++; +} + +char *get_word(fp, word) +register FILE *fp; +register char *word; +{ + register int ch, i = 0; + while ((ch = getc(fp)) != EOF && isspace(ch)) + ; + word[i++] = ch; + while ((ch = getc(fp)) != EOF && ! isspace(ch)) + word[i++] = ch; + word[i++] = '\0'; + return word; +} + +/* + * Yes, I know this routine is a mess + */ +void read_cube(fp, PLA) +register FILE *fp; +pPLA PLA; +{ + register int var, i; + pcube cf = cube.temp[0], cr = cube.temp[1], cd = cube.temp[2]; + bool savef = FALSE, saved = FALSE, saver = FALSE; + char token[256]; /* for kiss read hack */ + int varx, first, last, offset; /* for kiss read hack */ + + set_clear(cf, cube.size); + + /* Loop and read binary variables */ + for(var = 0; var < cube.num_binary_vars; var++) + switch(getc(fp)) { + case EOF: + goto bad_char; + case '\n': + if (! line_length_error) + (void) fprintf(stderr, "product term(s) %s\n", + "span more than one line (warning only)"); + line_length_error = TRUE; + lineno++; + var--; + break; + case ' ': case '|': case '\t': + var--; + break; + case '2': case '-': + set_insert(cf, var*2+1); + case '0': + set_insert(cf, var*2); + break; + case '1': + set_insert(cf, var*2+1); + break; + case '?': + break; + default: + goto bad_char; + } + + + /* Loop for the all but one of the multiple-valued variables */ + for(var = cube.num_binary_vars; var < cube.num_vars-1; var++) + + /* Read a symbolic multiple-valued variable */ + if (cube.part_size[var] < 0) { + (void) fscanf(fp, "%s", token); + if (equal(token, "-") || equal(token, "ANY")) { + if (kiss && var == cube.num_vars - 2) { + /* leave it empty */ + } else { + /* make it full */ + set_or(cf, cf, cube.var_mask[var]); + } + } else if (equal(token, "~")) { + ; + /* leave it empty ... (?) */ + } else { + if (kiss && var == cube.num_vars - 2) + varx = var - 1, offset = ABS(cube.part_size[var-1]); + else + varx = var, offset = 0; + /* Find the symbolic label in the label table */ + first = cube.first_part[varx]; + last = cube.last_part[varx]; + for(i = first; i <= last; i++) + if (PLA->label[i] == (char *) NULL) { + PLA->label[i] = util_strsav(token); /* add new label */ + set_insert(cf, i+offset); + break; + } else if (equal(PLA->label[i], token)) { + set_insert(cf, i+offset); /* use column i */ + break; + } + if (i > last) { + (void) fprintf(stderr, +"declared size of variable %d (counting from variable 0) is too small\n", var); + exit(-1); + } + } + + } else for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) + switch (getc(fp)) { + case EOF: + goto bad_char; + case '\n': + if (! line_length_error) + (void) fprintf(stderr, "product term(s) %s\n", + "span more than one line (warning only)"); + line_length_error = TRUE; + lineno++; + i--; + break; + case ' ': case '|': case '\t': + i--; + break; + case '1': + set_insert(cf, i); + case '0': + break; + default: + goto bad_char; + } + + /* Loop for last multiple-valued variable */ + if (kiss) { + saver = savef = TRUE; + (void) set_xor(cr, cf, cube.var_mask[cube.num_vars - 2]); + } else + set_copy(cr, cf); + set_copy(cd, cf); + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) + switch (getc(fp)) { + case EOF: + goto bad_char; + case '\n': + if (! line_length_error) + (void) fprintf(stderr, "product term(s) %s\n", + "span more than one line (warning only)"); + line_length_error = TRUE; + lineno++; + i--; + break; + case ' ': case '|': case '\t': + i--; + break; + case '4': case '1': + if (PLA->pla_type & F_type) + set_insert(cf, i), savef = TRUE; + break; + case '3': case '0': + if (PLA->pla_type & R_type) + set_insert(cr, i), saver = TRUE; + break; + case '2': case '-': + if (PLA->pla_type & D_type) + set_insert(cd, i), saved = TRUE; + case '~': + break; + default: + goto bad_char; + } + if (savef) PLA->F = sf_addset(PLA->F, cf); + if (saved) PLA->D = sf_addset(PLA->D, cd); + if (saver) PLA->R = sf_addset(PLA->R, cr); + return; + +bad_char: + (void) fprintf(stderr, "(warning): input line #%d ignored\n", lineno); + skip_line(fp, stdout, TRUE); + return; +} +void parse_pla(fp, PLA) +IN FILE *fp; +INOUT pPLA PLA; +{ + int i, var, ch, np, last; + char word[256]; + + lineno = 1; + line_length_error = FALSE; + +loop: + switch(ch = getc(fp)) { + case EOF: + return; + + case '\n': + lineno++; + + case ' ': case '\t': case '\f': case '\r': + break; + + case '#': + (void) ungetc(ch, fp); + skip_line(fp, stdout, echo_comments); + break; + + case '.': + /* .i gives the cube input size (binary-functions only) */ + if (equal(get_word(fp, word), "i")) { + if (cube.fullset != NULL) { + (void) fprintf(stderr, "extra .i ignored\n"); + skip_line(fp, stdout, /* echo */ FALSE); + } else { + if (fscanf(fp, "%d", &cube.num_binary_vars) != 1) + fatal("error reading .i"); + cube.num_vars = cube.num_binary_vars + 1; + cube.part_size = ALLOC(int, cube.num_vars); + } + + /* .o gives the cube output size (binary-functions only) */ + } else if (equal(word, "o")) { + if (cube.fullset != NULL) { + (void) fprintf(stderr, "extra .o ignored\n"); + skip_line(fp, stdout, /* echo */ FALSE); + } else { + if (cube.part_size == NULL) + fatal(".o cannot appear before .i"); + if (fscanf(fp, "%d", &(cube.part_size[cube.num_vars-1]))!=1) + fatal("error reading .o"); + cube_setup(); + PLA_labels(PLA); + } + + /* .mv gives the cube size for a multiple-valued function */ + } else if (equal(word, "mv")) { + if (cube.fullset != NULL) { + (void) fprintf(stderr, "extra .mv ignored\n"); + skip_line(fp, stdout, /* echo */ FALSE); + } else { + if (cube.part_size != NULL) + fatal("cannot mix .i and .mv"); + if (fscanf(fp,"%d %d", + &cube.num_vars,&cube.num_binary_vars) != 2) + fatal("error reading .mv"); + if (cube.num_binary_vars < 0) +fatal("num_binary_vars (second field of .mv) cannot be negative"); + if (cube.num_vars < cube.num_binary_vars) + fatal( +"num_vars (1st field of .mv) must exceed num_binary_vars (2nd field of .mv)"); + cube.part_size = ALLOC(int, cube.num_vars); + for(var=cube.num_binary_vars; var < cube.num_vars; var++) + if (fscanf(fp, "%d", &(cube.part_size[var])) != 1) + fatal("error reading .mv"); + cube_setup(); + PLA_labels(PLA); + } + + /* .p gives the number of product terms -- we ignore it */ + } else if (equal(word, "p")) + (void) fscanf(fp, "%d", &np); + /* .e and .end specify the end of the file */ + else if (equal(word, "e") || equal(word,"end")) { + if (cube.fullset == NULL) { + /* fatal("unknown PLA size, need .i/.o or .mv");*/ + } else if (PLA->F == NULL) { + PLA->F = new_cover(10); + PLA->D = new_cover(10); + PLA->R = new_cover(10); + } + return; + } + /* .kiss turns on the kiss-hack option */ + else if (equal(word, "kiss")) + kiss = TRUE; + + /* .type specifies a logical type for the PLA */ + else if (equal(word, "type")) { + (void) get_word(fp, word); + for(i = 0; pla_types[i].key != 0; i++) + if (equal(pla_types[i].key + 1, word)) { + PLA->pla_type = pla_types[i].value; + break; + } + if (pla_types[i].key == 0) + fatal("unknown type in .type command"); + + /* parse the labels */ + } else if (equal(word, "ilb")) { + if (cube.fullset == NULL) + fatal("PLA size must be declared before .ilb or .ob"); + if (PLA->label == NULL) + PLA_labels(PLA); + for(var = 0; var < cube.num_binary_vars; var++) { + (void) get_word(fp, word); + i = cube.first_part[var]; + PLA->label[i+1] = util_strsav(word); + PLA->label[i] = ALLOC(char, strlen(word) + 6); + (void) sprintf(PLA->label[i], "%s.bar", word); + } + } else if (equal(word, "ob")) { + if (cube.fullset == NULL) + fatal("PLA size must be declared before .ilb or .ob"); + if (PLA->label == NULL) + PLA_labels(PLA); + var = cube.num_vars - 1; + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + (void) get_word(fp, word); + PLA->label[i] = util_strsav(word); + } + /* .label assigns labels to multiple-valued variables */ + } else if (equal(word, "label")) { + if (cube.fullset == NULL) + fatal("PLA size must be declared before .label"); + if (PLA->label == NULL) + PLA_labels(PLA); + if (fscanf(fp, "var=%d", &var) != 1) + fatal("Error reading labels"); + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + (void) get_word(fp, word); + PLA->label[i] = util_strsav(word); + } + + } else if (equal(word, "symbolic")) { + symbolic_t *newlist, *p1; + if (read_symbolic(fp, PLA, word, &newlist)) { + if (PLA->symbolic == NIL(symbolic_t)) { + PLA->symbolic = newlist; + } else { + for(p1=PLA->symbolic;p1->next!=NIL(symbolic_t); + p1=p1->next){ + } + p1->next = newlist; + } + } else { + fatal("error reading .symbolic"); + } + + } else if (equal(word, "symbolic-output")) { + symbolic_t *newlist, *p1; + if (read_symbolic(fp, PLA, word, &newlist)) { + if (PLA->symbolic_output == NIL(symbolic_t)) { + PLA->symbolic_output = newlist; + } else { + for(p1=PLA->symbolic_output;p1->next!=NIL(symbolic_t); + p1=p1->next){ + } + p1->next = newlist; + } + } else { + fatal("error reading .symbolic-output"); + } + + /* .phase allows a choice of output phases */ + } else if (equal(word, "phase")) { + if (cube.fullset == NULL) + fatal("PLA size must be declared before .phase"); + if (PLA->phase != NULL) { + (void) fprintf(stderr, "extra .phase ignored\n"); + skip_line(fp, stdout, /* echo */ FALSE); + } else { + do ch = getc(fp); while (ch == ' ' || ch == '\t'); + (void) ungetc(ch, fp); + PLA->phase = set_save(cube.fullset); + last = cube.last_part[cube.num_vars - 1]; + for(i=cube.first_part[cube.num_vars - 1]; i <= last; i++) + if ((ch = getc(fp)) == '0') + set_remove(PLA->phase, i); + else if (ch != '1') + fatal("only 0 or 1 allowed in phase description"); + } + + /* .pair allows for bit-pairing input variables */ + } else if (equal(word, "pair")) { + int j; + if (PLA->pair != NULL) { + (void) fprintf(stderr, "extra .pair ignored\n"); + } else { + ppair pair; + PLA->pair = pair = ALLOC(pair_t, 1); + if (fscanf(fp, "%d", &(pair->cnt)) != 1) + fatal("syntax error in .pair"); + pair->var1 = ALLOC(int, pair->cnt); + pair->var2 = ALLOC(int, pair->cnt); + for(i = 0; i < pair->cnt; i++) { + (void) get_word(fp, word); + if (word[0] == '(') (void) strcpy(word, word+1); + if (label_index(PLA, word, &var, &j)) { + pair->var1[i] = var+1; + } else { + fatal("syntax error in .pair"); + } + + (void) get_word(fp, word); + if (word[strlen(word)-1] == ')') { + word[strlen(word)-1]='\0'; + } + if (label_index(PLA, word, &var, &j)) { + pair->var2[i] = var+1; + } else { + fatal("syntax error in .pair"); + } + } + } + + } else { + if (echo_unknown_commands) + printf("%c%s ", ch, word); + skip_line(fp, stdout, echo_unknown_commands); + } + break; + default: + (void) ungetc(ch, fp); + if (cube.fullset == NULL) { +/* fatal("unknown PLA size, need .i/.o or .mv");*/ + if (echo_comments) + putchar('#'); + skip_line(fp, stdout, echo_comments); + break; + } + if (PLA->F == NULL) { + PLA->F = new_cover(10); + PLA->D = new_cover(10); + PLA->R = new_cover(10); + } + read_cube(fp, PLA); + } + goto loop; +} +/* + read_pla -- read a PLA from a file + + Input stops when ".e" is encountered in the input file, or upon reaching + end of file. + + Returns the PLA in the variable PLA after massaging the "symbolic" + representation into a positional cube notation of the ON-set, OFF-set, + and the DC-set. + + needs_dcset and needs_offset control the computation of the OFF-set + and DC-set (i.e., if either needs to be computed, then it will be + computed via complement only if the corresponding option is TRUE.) + pla_type specifies the interpretation to be used when reading the + PLA. + + The phase of the output functions is adjusted according to the + global option "pos" or according to an imbedded .phase option in + the input file. Note that either phase option implies that the + OFF-set be computed regardless of whether the caller needs it + explicitly or not. + + Bit pairing of the binary variables is performed according to an + imbedded .pair option in the input file. + + The global cube structure also reflects the sizes of the PLA which + was just read. If these fields have already been set, then any + subsequent PLA must conform to these sizes. + + The global flags trace and summary control the output produced + during the read. + + Returns a status code as a result: + EOF (-1) : End of file reached before any data was read + > 0 : Operation successful +*/ + +int read_pla(fp, needs_dcset, needs_offset, pla_type, PLA_return) +IN FILE *fp; +IN bool needs_dcset, needs_offset; +IN int pla_type; +OUT pPLA *PLA_return; +{ + pPLA PLA; + int i, second, third; + long time; + cost_t cost; + + /* Allocate and initialize the PLA structure */ + PLA = *PLA_return = new_PLA(); + PLA->pla_type = pla_type; + + /* Read the pla */ + time = ptime(); + parse_pla(fp, PLA); + + /* Check for nothing on the file -- implies reached EOF */ + if (PLA->F == NULL) { + return EOF; + } + + /* This hack merges the next-state field with the outputs */ + for(i = 0; i < cube.num_vars; i++) { + cube.part_size[i] = ABS(cube.part_size[i]); + } + if (kiss) { + third = cube.num_vars - 3; + second = cube.num_vars - 2; + if (cube.part_size[third] != cube.part_size[second]) { + (void) fprintf(stderr," with .kiss option, third to last and second\n"); + (void) fprintf(stderr, "to last variables must be the same size.\n"); + return EOF; + } + for(i = 0; i < cube.part_size[second]; i++) { + PLA->label[i + cube.first_part[second]] = + util_strsav(PLA->label[i + cube.first_part[third]]); + } + cube.part_size[second] += cube.part_size[cube.num_vars-1]; + cube.num_vars--; + setdown_cube(); + cube_setup(); + } + + if (trace) { + totals(time, READ_TIME, PLA->F, &cost); + } + + /* Decide how to break PLA into ON-set, OFF-set and DC-set */ + time = ptime(); + if (pos || PLA->phase != NULL || PLA->symbolic_output != NIL(symbolic_t)) { + needs_offset = TRUE; + } + if (needs_offset && (PLA->pla_type==F_type || PLA->pla_type==FD_type)) { + free_cover(PLA->R); + PLA->R = complement(cube2list(PLA->F, PLA->D)); + } else if (needs_dcset && PLA->pla_type == FR_type) { + pcover X; + free_cover(PLA->D); + /* hack, why not? */ + X = d1merge(sf_join(PLA->F, PLA->R), cube.num_vars - 1); + PLA->D = complement(cube1list(X)); + free_cover(X); + } else if (PLA->pla_type == R_type || PLA->pla_type == DR_type) { + free_cover(PLA->F); + PLA->F = complement(cube2list(PLA->D, PLA->R)); + } + + if (trace) { + totals(time, COMPL_TIME, PLA->R, &cost); + } + + /* Check for phase rearrangement of the functions */ + if (pos) { + pcover onset = PLA->F; + PLA->F = PLA->R; + PLA->R = onset; + PLA->phase = new_cube(); + set_diff(PLA->phase, cube.fullset, cube.var_mask[cube.num_vars-1]); + } else if (PLA->phase != NULL) { + (void) set_phase(PLA); + } + + /* Setup minimization for two-bit decoders */ + if (PLA->pair != (ppair) NULL) { + set_pair(PLA); + } + + if (PLA->symbolic != NIL(symbolic_t)) { + EXEC(map_symbolic(PLA), "MAP-INPUT ", PLA->F); + } + if (PLA->symbolic_output != NIL(symbolic_t)) { + EXEC(map_output_symbolic(PLA), "MAP-OUTPUT ", PLA->F); + if (needs_offset) { + free_cover(PLA->R); +EXECUTE(PLA->R=complement(cube2list(PLA->F,PLA->D)), COMPL_TIME, PLA->R, cost); + } + } + + return 1; +} + +void PLA_summary(PLA) +pPLA PLA; +{ + int var, i; + symbolic_list_t *p2; + symbolic_t *p1; + + printf("# PLA is %s", PLA->filename); + if (cube.num_binary_vars == cube.num_vars - 1) + printf(" with %d inputs and %d outputs\n", + cube.num_binary_vars, cube.part_size[cube.num_vars - 1]); + else { + printf(" with %d variables (%d binary, mv sizes", + cube.num_vars, cube.num_binary_vars); + for(var = cube.num_binary_vars; var < cube.num_vars; var++) + printf(" %d", cube.part_size[var]); + printf(")\n"); + } + printf("# ON-set cost is %s\n", print_cost(PLA->F)); + printf("# OFF-set cost is %s\n", print_cost(PLA->R)); + printf("# DC-set cost is %s\n", print_cost(PLA->D)); + if (PLA->phase != NULL) + printf("# phase is %s\n", pc1(PLA->phase)); + if (PLA->pair != NULL) { + printf("# two-bit decoders:"); + for(i = 0; i < PLA->pair->cnt; i++) + printf(" (%d %d)", PLA->pair->var1[i], PLA->pair->var2[i]); + printf("\n"); + } + if (PLA->symbolic != NIL(symbolic_t)) { + for(p1 = PLA->symbolic; p1 != NIL(symbolic_t); p1 = p1->next) { + printf("# symbolic: "); + for(p2=p1->symbolic_list; p2!=NIL(symbolic_list_t); p2=p2->next) { + printf(" %d", p2->variable); + } + printf("\n"); + } + } + if (PLA->symbolic_output != NIL(symbolic_t)) { + for(p1 = PLA->symbolic_output; p1 != NIL(symbolic_t); p1 = p1->next) { + printf("# output symbolic: "); + for(p2=p1->symbolic_list; p2!=NIL(symbolic_list_t); p2=p2->next) { + printf(" %d", p2->pos); + } + printf("\n"); + } + } + (void) fflush(stdout); +} + + +pPLA new_PLA() +{ + pPLA PLA; + + PLA = ALLOC(PLA_t, 1); + PLA->F = PLA->D = PLA->R = (pcover) NULL; + PLA->phase = (pcube) NULL; + PLA->pair = (ppair) NULL; + PLA->label = (char **) NULL; + PLA->filename = (char *) NULL; + PLA->pla_type = 0; + PLA->symbolic = NIL(symbolic_t); + PLA->symbolic_output = NIL(symbolic_t); + return PLA; +} + + +PLA_labels(PLA) +pPLA PLA; +{ + int i; + + PLA->label = ALLOC(char *, cube.size); + for(i = 0; i < cube.size; i++) + PLA->label[i] = (char *) NULL; +} + + +void free_PLA(PLA) +pPLA PLA; +{ + symbolic_list_t *p2, *p2next; + symbolic_t *p1, *p1next; + int i; + + if (PLA->F != (pcover) NULL) + free_cover(PLA->F); + if (PLA->R != (pcover) NULL) + free_cover(PLA->R); + if (PLA->D != (pcover) NULL) + free_cover(PLA->D); + if (PLA->phase != (pcube) NULL) + free_cube(PLA->phase); + if (PLA->pair != (ppair) NULL) { + FREE(PLA->pair->var1); + FREE(PLA->pair->var2); + FREE(PLA->pair); + } + if (PLA->label != NULL) { + for(i = 0; i < cube.size; i++) + if (PLA->label[i] != NULL) + FREE(PLA->label[i]); + FREE(PLA->label); + } + if (PLA->filename != NULL) { + FREE(PLA->filename); + } + for(p1 = PLA->symbolic; p1 != NIL(symbolic_t); p1 = p1next) { + for(p2 = p1->symbolic_list; p2 != NIL(symbolic_list_t); p2 = p2next) { + p2next = p2->next; + FREE(p2); + } + p1next = p1->next; + FREE(p1); + } + PLA->symbolic = NIL(symbolic_t); + for(p1 = PLA->symbolic_output; p1 != NIL(symbolic_t); p1 = p1next) { + for(p2 = p1->symbolic_list; p2 != NIL(symbolic_list_t); p2 = p2next) { + p2next = p2->next; + FREE(p2); + } + p1next = p1->next; + FREE(p1); + } + PLA->symbolic_output = NIL(symbolic_t); + FREE(PLA); +} + + +int read_symbolic(fp, PLA, word, retval) +FILE *fp; +pPLA PLA; +char *word; /* scratch string for words */ +symbolic_t **retval; +{ + symbolic_list_t *listp, *prev_listp; + symbolic_label_t *labelp, *prev_labelp; + symbolic_t *newlist; + int i, var; + + newlist = ALLOC(symbolic_t, 1); + newlist->next = NIL(symbolic_t); + newlist->symbolic_list = NIL(symbolic_list_t); + newlist->symbolic_list_length = 0; + newlist->symbolic_label = NIL(symbolic_label_t); + newlist->symbolic_label_length = 0; + prev_listp = NIL(symbolic_list_t); + prev_labelp = NIL(symbolic_label_t); + + for(;;) { + (void) get_word(fp, word); + if (equal(word, ";")) + break; + if (label_index(PLA, word, &var, &i)) { + listp = ALLOC(symbolic_list_t, 1); + listp->variable = var; + listp->pos = i; + listp->next = NIL(symbolic_list_t); + if (prev_listp == NIL(symbolic_list_t)) { + newlist->symbolic_list = listp; + } else { + prev_listp->next = listp; + } + prev_listp = listp; + newlist->symbolic_list_length++; + } else { + return FALSE; + } + } + + for(;;) { + (void) get_word(fp, word); + if (equal(word, ";")) + break; + labelp = ALLOC(symbolic_label_t, 1); + labelp->label = util_strsav(word); + labelp->next = NIL(symbolic_label_t); + if (prev_labelp == NIL(symbolic_label_t)) { + newlist->symbolic_label = labelp; + } else { + prev_labelp->next = labelp; + } + prev_labelp = labelp; + newlist->symbolic_label_length++; + } + + *retval = newlist; + return TRUE; +} + + +int label_index(PLA, word, varp, ip) +pPLA PLA; +char *word; +int *varp; +int *ip; +{ + int var, i; + + if (PLA->label == NIL(char *) || PLA->label[0] == NIL(char)) { + if (sscanf(word, "%d", varp) == 1) { + *ip = *varp; + return TRUE; + } + } else { + for(var = 0; var < cube.num_vars; var++) { + for(i = 0; i < cube.part_size[var]; i++) { + if (equal(PLA->label[cube.first_part[var]+i], word)) { + *varp = var; + *ip = i; + return TRUE; + } + } + } + } + return FALSE; +} diff --git a/src/misc/espresso/cvrm.c b/src/misc/espresso/cvrm.c new file mode 100644 index 00000000..7d42d6e3 --- /dev/null +++ b/src/misc/espresso/cvrm.c @@ -0,0 +1,539 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +/* + module: cvrm.c + Purpose: miscellaneous cover manipulation + a) verify two covers are equal, check consistency of a cover + b) unravel a multiple-valued cover into minterms + c) sort covers +*/ + +#include "espresso.h" + + +static void cb_unravel(c, start, end, startbase, B1) +IN register pcube c; +IN int start, end; +IN pcube startbase; +INOUT pcover B1; +{ + pcube base = cube.temp[0], p, last; + int expansion, place, skip, var, size, offset; + register int i, j, k, n; + + /* Determine how many cubes it will blow up into, and create a mask + for those parts that have only a single coordinate + */ + expansion = 1; + (void) set_copy(base, startbase); + for(var = start; var <= end; var++) { + if ((size = set_dist(c, cube.var_mask[var])) < 2) { + (void) set_or(base, base, cube.var_mask[var]); + } else { + expansion *= size; + } + } + (void) set_and(base, c, base); + + /* Add the unravelled sets starting at the last element of B1 */ + offset = B1->count; + B1->count += expansion; + foreach_remaining_set(B1, last, GETSET(B1, offset-1), p) { + INLINEset_copy(p, base); + } + + place = expansion; + for(var = start; var <= end; var++) { + if ((size = set_dist(c, cube.var_mask[var])) > 1) { + skip = place; + place = place / size; + n = 0; + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + if (is_in_set(c, i)) { + for(j = n; j < expansion; j += skip) { + for(k = 0; k < place; k++) { + p = GETSET(B1, j+k+offset); + (void) set_insert(p, i); + } + } + n += place; + } + } + } + } +} + + +pcover unravel_range(B, start, end) +IN pcover B; +IN int start, end; +{ + pcover B1; + int var, total_size, expansion, size; + register pcube p, last, startbase = cube.temp[1]; + + /* Create the starting base for those variables not being unravelled */ + (void) set_copy(startbase, cube.emptyset); + for(var = 0; var < start; var++) + (void) set_or(startbase, startbase, cube.var_mask[var]); + for(var = end+1; var < cube.num_vars; var++) + (void) set_or(startbase, startbase, cube.var_mask[var]); + + /* Determine how many cubes it will blow up into */ + total_size = 0; + foreach_set(B, last, p) { + expansion = 1; + for(var = start; var <= end; var++) + if ((size = set_dist(p, cube.var_mask[var])) >= 2) + if ((expansion *= size) > 1000000) + fatal("unreasonable expansion in unravel"); + total_size += expansion; + } + + /* We can now allocate a cover of exactly the correct size */ + B1 = new_cover(total_size); + foreach_set(B, last, p) { + cb_unravel(p, start, end, startbase, B1); + } + free_cover(B); + return B1; +} + + +pcover unravel(B, start) +IN pcover B; +IN int start; +{ + return unravel_range(B, start, cube.num_vars-1); +} + +/* lex_sort -- sort cubes in a standard lexical fashion */ +pcover lex_sort(T) +pcover T; +{ + pcover T1 = sf_unlist(sf_sort(T, lex_order), T->count, T->sf_size); + free_cover(T); + return T1; +} + + +/* size_sort -- sort cubes by their size */ +pcover size_sort(T) +pcover T; +{ + pcover T1 = sf_unlist(sf_sort(T, descend), T->count, T->sf_size); + free_cover(T); + return T1; +} + + +/* mini_sort -- sort cubes according to the heuristics of mini */ +pcover mini_sort(F, compare) +pcover F; +int (*compare)(); +{ + register int *count, cnt, n = cube.size, i; + register pcube p, last; + pcover F_sorted; + pcube *F1; + + /* Perform a column sum over the set family */ + count = sf_count(F); + + /* weight is "inner product of the cube and the column sums" */ + foreach_set(F, last, p) { + cnt = 0; + for(i = 0; i < n; i++) + if (is_in_set(p, i)) + cnt += count[i]; + PUTSIZE(p, cnt); + } + FREE(count); + + /* use qsort to sort the array */ + qsort((char *) (F1 = sf_list(F)), F->count, sizeof(pcube), compare); + F_sorted = sf_unlist(F1, F->count, F->sf_size); + free_cover(F); + + return F_sorted; +} + + +/* sort_reduce -- Espresso strategy for ordering the cubes before reduction */ +pcover sort_reduce(T) +IN pcover T; +{ + register pcube p, last, largest = NULL; + register int bestsize = -1, size, n = cube.num_vars; + pcover T_sorted; + pcube *T1; + + if (T->count == 0) + return T; + + /* find largest cube */ + foreach_set(T, last, p) + if ((size = set_ord(p)) > bestsize) + largest = p, bestsize = size; + + foreach_set(T, last, p) + PUTSIZE(p, ((n - cdist(largest,p)) << 7) + MIN(set_ord(p),127)); + + qsort((char *) (T1 = sf_list(T)), T->count, sizeof(pcube), (int (*)()) descend); + T_sorted = sf_unlist(T1, T->count, T->sf_size); + free_cover(T); + + return T_sorted; +} + +pcover random_order(F) +register pcover F; +{ + pset temp; + register int i, k; +#ifdef RANDOM + long random(); +#endif + + temp = set_new(F->sf_size); + for(i = F->count - 1; i > 0; i--) { + /* Choose a random number between 0 and i */ +#ifdef RANDOM + k = random() % i; +#else + /* this is not meant to be really used; just provides an easy + "out" if random() and srandom() aren't around + */ + k = (i*23 + 997) % i; +#endif + /* swap sets i and k */ + (void) set_copy(temp, GETSET(F, k)); + (void) set_copy(GETSET(F, k), GETSET(F, i)); + (void) set_copy(GETSET(F, i), temp); + } + set_free(temp); + return F; +} + +/* + * cubelist_partition -- take a cubelist T and see if it has any components; + * if so, return cubelist's of the two partitions A and B; the return value + * is the size of the partition; if not, A and B + * are undefined and the return value is 0 + */ +int cubelist_partition(T, A, B, comp_debug) +pcube *T; /* a list of cubes */ +pcube **A, **B; /* cubelist of partition and remainder */ +unsigned int comp_debug; +{ + register pcube *T1, p, seed, cof; + pcube *A1, *B1; + bool change; + int count, numcube; + + numcube = CUBELISTSIZE(T); + + /* Mark all cubes -- covered cubes belong to the partition */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + RESET(p, COVERED); + } + + /* + * Extract a partition from the cubelist T; start with the first cube as a + * seed, and then pull in all cubes which share a variable with the seed; + * iterate until no new cubes are brought into the partition. + */ + seed = set_save(T[2]); + cof = T[0]; + SET(T[2], COVERED); + count = 1; + + do { + change = FALSE; + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (! TESTP(p, COVERED) && ccommon(p, seed, cof)) { + INLINEset_and(seed, seed, p); + SET(p, COVERED); + change = TRUE; + count++; + } + + } + } while (change); + + set_free(seed); + + if (comp_debug) { + (void) printf("COMPONENT_REDUCTION: split into %d %d\n", + count, numcube - count); + } + + if (count != numcube) { + /* Allocate and setup the cubelist's for the two partitions */ + *A = A1 = ALLOC(pcube, numcube+3); + *B = B1 = ALLOC(pcube, numcube+3); + (*A)[0] = set_save(T[0]); + (*B)[0] = set_save(T[0]); + A1 = *A + 2; + B1 = *B + 2; + + /* Loop over the cubes in T and distribute to A and B */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (TESTP(p, COVERED)) { + *A1++ = p; + } else { + *B1++ = p; + } + } + + /* Stuff needed at the end of the cubelist's */ + *A1++ = NULL; + (*A)[1] = (pcube) A1; + *B1++ = NULL; + (*B)[1] = (pcube) B1; + } + + return numcube - count; +} + +/* + * quick cofactor against a single output function + */ +pcover cof_output(T, i) +pcover T; +register int i; +{ + pcover T1; + register pcube p, last, pdest, mask; + + mask = cube.var_mask[cube.output]; + T1 = new_cover(T->count); + foreach_set(T, last, p) { + if (is_in_set(p, i)) { + pdest = GETSET(T1, T1->count++); + INLINEset_or(pdest, p, mask); + RESET(pdest, PRIME); + } + } + return T1; +} + + +/* + * quick intersection against a single output function + */ +pcover uncof_output(T, i) +pcover T; +int i; +{ + register pcube p, last, mask; + + if (T == NULL) { + return T; + } + + mask = cube.var_mask[cube.output]; + foreach_set(T, last, p) { + INLINEset_diff(p, p, mask); + set_insert(p, i); + } + return T; +} + + +/* + * A generic routine to perform an operation for each output function + * + * func() is called with a PLA for each output function (with the output + * part effectively removed). + * func1() is called after reforming the equivalent output function + * + * Each function returns TRUE if process is to continue + */ +foreach_output_function(PLA, func, func1) +pPLA PLA; +int (*func)(); +int (*func1)(); +{ + pPLA PLA1; + int i; + + /* Loop for each output function */ + for(i = 0; i < cube.part_size[cube.output]; i++) { + + /* cofactor on the output part */ + PLA1 = new_PLA(); + PLA1->F = cof_output(PLA->F, i + cube.first_part[cube.output]); + PLA1->R = cof_output(PLA->R, i + cube.first_part[cube.output]); + PLA1->D = cof_output(PLA->D, i + cube.first_part[cube.output]); + + /* Call a routine to do something with the cover */ + if ((*func)(PLA1, i) == 0) { + free_PLA(PLA1); + return; + } + + /* intersect with the particular output part again */ + PLA1->F = uncof_output(PLA1->F, i + cube.first_part[cube.output]); + PLA1->R = uncof_output(PLA1->R, i + cube.first_part[cube.output]); + PLA1->D = uncof_output(PLA1->D, i + cube.first_part[cube.output]); + + /* Call a routine to do something with the final result */ + if ((*func1)(PLA1, i) == 0) { + free_PLA(PLA1); + return; + } + + /* Cleanup for next go-around */ + free_PLA(PLA1); + + + } +} + +static pcover Fmin; +static pcube phase; + +/* + * minimize each output function individually + */ +void so_espresso(PLA, strategy) +pPLA PLA; +int strategy; +{ + Fmin = new_cover(PLA->F->count); + if (strategy == 0) { + foreach_output_function(PLA, so_do_espresso, so_save); + } else { + foreach_output_function(PLA, so_do_exact, so_save); + } + sf_free(PLA->F); + PLA->F = Fmin; +} + + +/* + * minimize each output function, choose function or complement based on the + * one with the fewer number of terms + */ +void so_both_espresso(PLA, strategy) +pPLA PLA; +int strategy; +{ + phase = set_save(cube.fullset); + Fmin = new_cover(PLA->F->count); + if (strategy == 0) { + foreach_output_function(PLA, so_both_do_espresso, so_both_save); + } else { + foreach_output_function(PLA, so_both_do_exact, so_both_save); + } + sf_free(PLA->F); + PLA->F = Fmin; + PLA->phase = phase; +} + + +int so_do_espresso(PLA, i) +pPLA PLA; +int i; +{ + char word[32]; + + /* minimize the single-output function (on-set) */ + skip_make_sparse = 1; + (void) sprintf(word, "ESPRESSO-POS(%d)", i); + EXEC_S(PLA->F = espresso(PLA->F, PLA->D, PLA->R), word, PLA->F); + return 1; +} + + +int so_do_exact(PLA, i) +pPLA PLA; +int i; +{ + char word[32]; + + /* minimize the single-output function (on-set) */ + skip_make_sparse = 1; + (void) sprintf(word, "EXACT-POS(%d)", i); + EXEC_S(PLA->F = minimize_exact(PLA->F, PLA->D, PLA->R, 1), word, PLA->F); + return 1; +} + + +/*ARGSUSED*/ +int so_save(PLA, i) +pPLA PLA; +int i; +{ + Fmin = sf_append(Fmin, PLA->F); /* disposes of PLA->F */ + PLA->F = NULL; + return 1; +} + + +int so_both_do_espresso(PLA, i) +pPLA PLA; +int i; +{ + char word[32]; + + /* minimize the single-output function (on-set) */ + (void) sprintf(word, "ESPRESSO-POS(%d)", i); + skip_make_sparse = 1; + EXEC_S(PLA->F = espresso(PLA->F, PLA->D, PLA->R), word, PLA->F); + + /* minimize the single-output function (off-set) */ + (void) sprintf(word, "ESPRESSO-NEG(%d)", i); + skip_make_sparse = 1; + EXEC_S(PLA->R = espresso(PLA->R, PLA->D, PLA->F), word, PLA->R); + + return 1; +} + + +int so_both_do_exact(PLA, i) +pPLA PLA; +int i; +{ + char word[32]; + + /* minimize the single-output function (on-set) */ + (void) sprintf(word, "EXACT-POS(%d)", i); + skip_make_sparse = 1; + EXEC_S(PLA->F = minimize_exact(PLA->F, PLA->D, PLA->R, 1), word, PLA->F); + + /* minimize the single-output function (off-set) */ + (void) sprintf(word, "EXACT-NEG(%d)", i); + skip_make_sparse = 1; + EXEC_S(PLA->R = minimize_exact(PLA->R, PLA->D, PLA->F, 1), word, PLA->R); + + return 1; +} + + +int so_both_save(PLA, i) +pPLA PLA; +int i; +{ + if (PLA->F->count > PLA->R->count) { + sf_free(PLA->F); + PLA->F = PLA->R; + PLA->R = NULL; + i += cube.first_part[cube.output]; + set_remove(phase, i); + } else { + sf_free(PLA->R); + PLA->R = NULL; + } + Fmin = sf_append(Fmin, PLA->F); + PLA->F = NULL; + return 1; +} diff --git a/src/misc/espresso/cvrmisc.c b/src/misc/espresso/cvrmisc.c new file mode 100644 index 00000000..0f3de195 --- /dev/null +++ b/src/misc/espresso/cvrmisc.c @@ -0,0 +1,142 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +#include "espresso.h" + + +/* cost -- compute the cost of a cover */ +void cover_cost(F, cost) +IN pcover F; +INOUT pcost cost; +{ + register pcube p, last; + pcube *T; + int var; + + /* use the routine used by cofactor to decide splitting variables */ + massive_count(T = cube1list(F)); + free_cubelist(T); + + cost->cubes = F->count; + cost->total = cost->in = cost->out = cost->mv = cost->primes = 0; + + /* Count transistors (zeros) for each binary variable (inputs) */ + for(var = 0; var < cube.num_binary_vars; var++) + cost->in += cdata.var_zeros[var]; + + /* Count transistors for each mv variable based on sparse/dense */ + for(var = cube.num_binary_vars; var < cube.num_vars - 1; var++) + if (cube.sparse[var]) + cost->mv += F->count * cube.part_size[var] - cdata.var_zeros[var]; + else + cost->mv += cdata.var_zeros[var]; + + /* Count the transistors (ones) for the output variable */ + if (cube.num_binary_vars != cube.num_vars) { + var = cube.num_vars - 1; + cost->out = F->count * cube.part_size[var] - cdata.var_zeros[var]; + } + + /* Count the number of nonprime cubes */ + foreach_set(F, last, p) + cost->primes += TESTP(p, PRIME) != 0; + + /* Count the total number of literals */ + cost->total = cost->in + cost->out + cost->mv; +} + + +/* fmt_cost -- return a string which reports the "cost" of a cover */ +char *fmt_cost(cost) +IN pcost cost; +{ + static char s[200]; + + if (cube.num_binary_vars == cube.num_vars - 1) + (void) sprintf(s, "c=%d(%d) in=%d out=%d tot=%d", + cost->cubes, cost->cubes - cost->primes, cost->in, + cost->out, cost->total); + else + (void) sprintf(s, "c=%d(%d) in=%d mv=%d out=%d", + cost->cubes, cost->cubes - cost->primes, cost->in, + cost->mv, cost->out); + return s; +} + + +char *print_cost(F) +IN pcover F; +{ + cost_t cost; + cover_cost(F, &cost); + return fmt_cost(&cost); +} + + +/* copy_cost -- copy a cost function from s to d */ +void copy_cost(s, d) +pcost s, d; +{ + d->cubes = s->cubes; + d->in = s->in; + d->out = s->out; + d->mv = s->mv; + d->total = s->total; + d->primes = s->primes; +} + + +/* size_stamp -- print single line giving the size of a cover */ +void size_stamp(T, name) +IN pcover T; +IN char *name; +{ + (void) printf("# %s\tCost is %s\n", name, print_cost(T)); + (void) fflush(stdout); +} + + +/* print_trace -- print a line reporting size and time after a function */ +void print_trace(T, name, time) +pcover T; +char *name; +long time; +{ + (void) printf("# %s\tTime was %s, cost is %s\n", + name, print_time(time), print_cost(T)); + (void) fflush(stdout); +} + + +/* totals -- add time spent in the function into the totals */ +void totals(time, i, T, cost) +long time; +int i; +pcover T; +pcost cost; +{ + time = ptime() - time; + total_time[i] += time; + total_calls[i]++; + cover_cost(T, cost); + if (trace) { + (void) printf("# %s\tTime was %s, cost is %s\n", + total_name[i], print_time(time), fmt_cost(cost)); + (void) fflush(stdout); + } +} + + +/* fatal -- report fatal error message and take a dive */ +void fatal(s) +char *s; +{ + (void) fprintf(stderr, "espresso: %s\n", s); + exit(1); +} diff --git a/src/misc/espresso/cvrout.c b/src/misc/espresso/cvrout.c new file mode 100644 index 00000000..4bd1c53b --- /dev/null +++ b/src/misc/espresso/cvrout.c @@ -0,0 +1,609 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +/* + module: cvrout.c + purpose: cube and cover output routines +*/ + +#include "espresso.h" + +void fprint_pla(fp, PLA, output_type) +INOUT FILE *fp; +IN pPLA PLA; +IN int output_type; +{ + int num; + register pcube last, p; + + if ((output_type & CONSTRAINTS_type) != 0) { + output_symbolic_constraints(fp, PLA, 0); + output_type &= ~ CONSTRAINTS_type; + if (output_type == 0) { + return; + } + } + + if ((output_type & SYMBOLIC_CONSTRAINTS_type) != 0) { + output_symbolic_constraints(fp, PLA, 1); + output_type &= ~ SYMBOLIC_CONSTRAINTS_type; + if (output_type == 0) { + return; + } + } + + if (output_type == PLEASURE_type) { + pls_output(PLA); + } else if (output_type == EQNTOTT_type) { + eqn_output(PLA); + } else if (output_type == KISS_type) { + kiss_output(fp, PLA); + } else { + fpr_header(fp, PLA, output_type); + + num = 0; + if (output_type & F_type) num += (PLA->F)->count; + if (output_type & D_type) num += (PLA->D)->count; + if (output_type & R_type) num += (PLA->R)->count; + (void) fprintf(fp, ".p %d\n", num); + + /* quick patch 01/17/85 to support TPLA ! */ + if (output_type == F_type) { + foreach_set(PLA->F, last, p) { + print_cube(fp, p, "01"); + } + (void) fprintf(fp, ".e\n"); + } else { + if (output_type & F_type) { + foreach_set(PLA->F, last, p) { + print_cube(fp, p, "~1"); + } + } + if (output_type & D_type) { + foreach_set(PLA->D, last, p) { + print_cube(fp, p, "~2"); + } + } + if (output_type & R_type) { + foreach_set(PLA->R, last, p) { + print_cube(fp, p, "~0"); + } + } + (void) fprintf(fp, ".end\n"); + } + } +} + +void fpr_header(fp, PLA, output_type) +FILE *fp; +pPLA PLA; +int output_type; +{ + register int i, var; + int first, last; + + /* .type keyword gives logical type */ + if (output_type != F_type) { + (void) fprintf(fp, ".type "); + if (output_type & F_type) putc('f', fp); + if (output_type & D_type) putc('d', fp); + if (output_type & R_type) putc('r', fp); + putc('\n', fp); + } + + /* Check for binary or multiple-valued labels */ + if (cube.num_mv_vars <= 1) { + (void) fprintf(fp, ".i %d\n", cube.num_binary_vars); + if (cube.output != -1) + (void) fprintf(fp, ".o %d\n", cube.part_size[cube.output]); + } else { + (void) fprintf(fp, ".mv %d %d", cube.num_vars, cube.num_binary_vars); + for(var = cube.num_binary_vars; var < cube.num_vars; var++) + (void) fprintf(fp, " %d", cube.part_size[var]); + (void) fprintf(fp, "\n"); + } + + /* binary valued labels */ + if (PLA->label != NIL(char *) && PLA->label[1] != NIL(char) + && cube.num_binary_vars > 0) { + (void) fprintf(fp, ".ilb"); + for(var = 0; var < cube.num_binary_vars; var++) + /* see (NIL) OUTLABELS comment below */ + if(INLABEL(var) == NIL(char)){ + (void) fprintf(fp, " (null)"); + } + else{ + (void) fprintf(fp, " %s", INLABEL(var)); + } + putc('\n', fp); + } + + /* output-part (last multiple-valued variable) labels */ + if (PLA->label != NIL(char *) && + PLA->label[cube.first_part[cube.output]] != NIL(char) + && cube.output != -1) { + (void) fprintf(fp, ".ob"); + for(i = 0; i < cube.part_size[cube.output]; i++) + /* (NIL) OUTLABELS caused espresso to segfault under solaris */ + if(OUTLABEL(i) == NIL(char)){ + (void) fprintf(fp, " (null)"); + } + else{ + (void) fprintf(fp, " %s", OUTLABEL(i)); + } + putc('\n', fp); + } + + /* multiple-valued labels */ + for(var = cube.num_binary_vars; var < cube.num_vars-1; var++) { + first = cube.first_part[var]; + last = cube.last_part[var]; + if (PLA->label != NULL && PLA->label[first] != NULL) { + (void) fprintf(fp, ".label var=%d", var); + for(i = first; i <= last; i++) { + (void) fprintf(fp, " %s", PLA->label[i]); + } + putc('\n', fp); + } + } + + if (PLA->phase != (pcube) NULL) { + first = cube.first_part[cube.output]; + last = cube.last_part[cube.output]; + (void) fprintf(fp, "#.phase "); + for(i = first; i <= last; i++) + putc(is_in_set(PLA->phase,i) ? '1' : '0', fp); + (void) fprintf(fp, "\n"); + } +} + +void pls_output(PLA) +IN pPLA PLA; +{ + register pcube last, p; + + (void) printf(".option unmerged\n"); + makeup_labels(PLA); + pls_label(PLA, stdout); + pls_group(PLA, stdout); + (void) printf(".p %d\n", PLA->F->count); + foreach_set(PLA->F, last, p) { + print_expanded_cube(stdout, p, PLA->phase); + } + (void) printf(".end\n"); +} + + +void pls_group(PLA, fp) +pPLA PLA; +FILE *fp; +{ + int var, i, col, len; + + (void) fprintf(fp, "\n.group"); + col = 6; + for(var = 0; var < cube.num_vars-1; var++) { + (void) fprintf(fp, " ("), col += 2; + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + len = strlen(PLA->label[i]); + if (col + len > 75) + (void) fprintf(fp, " \\\n"), col = 0; + else if (i != 0) + putc(' ', fp), col += 1; + (void) fprintf(fp, "%s", PLA->label[i]), col += len; + } + (void) fprintf(fp, ")"), col += 1; + } + (void) fprintf(fp, "\n"); +} + + +void pls_label(PLA, fp) +pPLA PLA; +FILE *fp; +{ + int var, i, col, len; + + (void) fprintf(fp, ".label"); + col = 6; + for(var = 0; var < cube.num_vars; var++) + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + len = strlen(PLA->label[i]); + if (col + len > 75) + (void) fprintf(fp, " \\\n"), col = 0; + else + putc(' ', fp), col += 1; + (void) fprintf(fp, "%s", PLA->label[i]), col += len; + } +} + + + +/* + eqntott output mode -- output algebraic equations +*/ +void eqn_output(PLA) +pPLA PLA; +{ + register pcube p, last; + register int i, var, col, len; + int x; + bool firstand, firstor; + + if (cube.output == -1) + fatal("Cannot have no-output function for EQNTOTT output mode"); + if (cube.num_mv_vars != 1) + fatal("Must have binary-valued function for EQNTOTT output mode"); + makeup_labels(PLA); + + /* Write a single equation for each output */ + for(i = 0; i < cube.part_size[cube.output]; i++) { + (void) printf("%s = ", OUTLABEL(i)); + col = strlen(OUTLABEL(i)) + 3; + firstor = TRUE; + + /* Write product terms for each cube in this output */ + foreach_set(PLA->F, last, p) + if (is_in_set(p, i + cube.first_part[cube.output])) { + if (firstor) + (void) printf("("), col += 1; + else + (void) printf(" | ("), col += 4; + firstor = FALSE; + firstand = TRUE; + + /* print out a product term */ + for(var = 0; var < cube.num_binary_vars; var++) + if ((x=GETINPUT(p, var)) != DASH) { + len = strlen(INLABEL(var)); + if (col+len > 72) + (void) printf("\n "), col = 4; + if (! firstand) + (void) printf("&"), col += 1; + firstand = FALSE; + if (x == ZERO) + (void) printf("!"), col += 1; + (void) printf("%s", INLABEL(var)), col += len; + } + (void) printf(")"), col += 1; + } + (void) printf(";\n\n"); + } +} + + +char *fmt_cube(c, out_map, s) +register pcube c; +register char *out_map, *s; +{ + register int i, var, last, len = 0; + + for(var = 0; var < cube.num_binary_vars; var++) { + s[len++] = "?01-" [GETINPUT(c, var)]; + } + for(var = cube.num_binary_vars; var < cube.num_vars - 1; var++) { + s[len++] = ' '; + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + s[len++] = "01" [is_in_set(c, i) != 0]; + } + } + if (cube.output != -1) { + last = cube.last_part[cube.output]; + s[len++] = ' '; + for(i = cube.first_part[cube.output]; i <= last; i++) { + s[len++] = out_map [is_in_set(c, i) != 0]; + } + } + s[len] = '\0'; + return s; +} + + +void print_cube(fp, c, out_map) +register FILE *fp; +register pcube c; +register char *out_map; +{ + register int i, var, ch; + int last; + + for(var = 0; var < cube.num_binary_vars; var++) { + ch = "?01-" [GETINPUT(c, var)]; + putc(ch, fp); + } + for(var = cube.num_binary_vars; var < cube.num_vars - 1; var++) { + putc(' ', fp); + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + ch = "01" [is_in_set(c, i) != 0]; + putc(ch, fp); + } + } + if (cube.output != -1) { + last = cube.last_part[cube.output]; + putc(' ', fp); + for(i = cube.first_part[cube.output]; i <= last; i++) { + ch = out_map [is_in_set(c, i) != 0]; + putc(ch, fp); + } + } + putc('\n', fp); +} + + +void print_expanded_cube(fp, c, phase) +register FILE *fp; +register pcube c; +pcube phase; +{ + register int i, var, ch; + char *out_map; + + for(var = 0; var < cube.num_binary_vars; var++) { + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + ch = "~1" [is_in_set(c, i) != 0]; + putc(ch, fp); + } + } + for(var = cube.num_binary_vars; var < cube.num_vars - 1; var++) { + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + ch = "1~" [is_in_set(c, i) != 0]; + putc(ch, fp); + } + } + if (cube.output != -1) { + var = cube.num_vars - 1; + putc(' ', fp); + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + if (phase == (pcube) NULL || is_in_set(phase, i)) { + out_map = "~1"; + } else { + out_map = "~0"; + } + ch = out_map[is_in_set(c, i) != 0]; + putc(ch, fp); + } + } + putc('\n', fp); +} + + +char *pc1(c) pcube c; +{static char s1[256];return fmt_cube(c, "01", s1);} +char *pc2(c) pcube c; +{static char s2[256];return fmt_cube(c, "01", s2);} + + +void debug_print(T, name, level) +pcube *T; +char *name; +int level; +{ + register pcube *T1, p, temp; + register int cnt; + + cnt = CUBELISTSIZE(T); + temp = new_cube(); + if (verbose_debug && level == 0) + (void) printf("\n"); + (void) printf("%s[%d]: ord(T)=%d\n", name, level, cnt); + if (verbose_debug) { + (void) printf("cofactor=%s\n", pc1(T[0])); + for(T1 = T+2, cnt = 1; (p = *T1++) != (pcube) NULL; cnt++) + (void) printf("%4d. %s\n", cnt, pc1(set_or(temp, p, T[0]))); + } + free_cube(temp); +} + + +void debug1_print(T, name, num) +pcover T; +char *name; +int num; +{ + register int cnt = 1; + register pcube p, last; + + if (verbose_debug && num == 0) + (void) printf("\n"); + (void) printf("%s[%d]: ord(T)=%d\n", name, num, T->count); + if (verbose_debug) + foreach_set(T, last, p) + (void) printf("%4d. %s\n", cnt++, pc1(p)); +} + + +void cprint(T) +pcover T; +{ + register pcube p, last; + + foreach_set(T, last, p) + (void) printf("%s\n", pc1(p)); +} + + +int makeup_labels(PLA) +pPLA PLA; +{ + int var, i, ind; + + if (PLA->label == (char **) NULL) + PLA_labels(PLA); + + for(var = 0; var < cube.num_vars; var++) + for(i = 0; i < cube.part_size[var]; i++) { + ind = cube.first_part[var] + i; + if (PLA->label[ind] == (char *) NULL) { + PLA->label[ind] = ALLOC(char, 15); + if (var < cube.num_binary_vars) + if ((i % 2) == 0) + (void) sprintf(PLA->label[ind], "v%d.bar", var); + else + (void) sprintf(PLA->label[ind], "v%d", var); + else + (void) sprintf(PLA->label[ind], "v%d.%d", var, i); + } + } +} + + +kiss_output(fp, PLA) +FILE *fp; +pPLA PLA; +{ + register pset last, p; + + foreach_set(PLA->F, last, p) { + kiss_print_cube(fp, PLA, p, "~1"); + } + foreach_set(PLA->D, last, p) { + kiss_print_cube(fp, PLA, p, "~2"); + } +} + + +kiss_print_cube(fp, PLA, p, out_string) +FILE *fp; +pPLA PLA; +pcube p; +char *out_string; +{ + register int i, var; + int part, x; + + for(var = 0; var < cube.num_binary_vars; var++) { + x = "?01-" [GETINPUT(p, var)]; + putc(x, fp); + } + + for(var = cube.num_binary_vars; var < cube.num_vars - 1; var++) { + putc(' ', fp); + if (setp_implies(cube.var_mask[var], p)) { + putc('-', fp); + } else { + part = -1; + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + if (is_in_set(p, i)) { + if (part != -1) { + fatal("more than 1 part in a symbolic variable\n"); + } + part = i; + } + } + if (part == -1) { + putc('~', fp); /* no parts, hope its an output ... */ + } else { + (void) fputs(PLA->label[part], fp); + } + } + } + + if ((var = cube.output) != -1) { + putc(' ', fp); + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + x = out_string [is_in_set(p, i) != 0]; + putc(x, fp); + } + } + + putc('\n', fp); +} + +output_symbolic_constraints(fp, PLA, output_symbolic) +FILE *fp; +pPLA PLA; +int output_symbolic; +{ + pset_family A; + register int i, j; + int size, var, npermute, *permute, *weight, noweight; + + if ((cube.num_vars - cube.num_binary_vars) <= 1) { + return; + } + makeup_labels(PLA); + + for(var=cube.num_binary_vars; var < cube.num_vars-1; var++) { + + /* pull out the columns for variable "var" */ + npermute = cube.part_size[var]; + permute = ALLOC(int, npermute); + for(i=0; i < npermute; i++) { + permute[i] = cube.first_part[var] + i; + } + A = sf_permute(sf_save(PLA->F), permute, npermute); + FREE(permute); + + + /* Delete the singletons and the full sets */ + noweight = 0; + for(i = 0; i < A->count; i++) { + size = set_ord(GETSET(A,i)); + if (size == 1 || size == A->sf_size) { + sf_delset(A, i--); + noweight++; + } + } + + + /* Count how many times each is duplicated */ + weight = ALLOC(int, A->count); + for(i = 0; i < A->count; i++) { + RESET(GETSET(A, i), COVERED); + } + for(i = 0; i < A->count; i++) { + weight[i] = 0; + if (! TESTP(GETSET(A,i), COVERED)) { + weight[i] = 1; + for(j = i+1; j < A->count; j++) { + if (setp_equal(GETSET(A,i), GETSET(A,j))) { + weight[i]++; + SET(GETSET(A,j), COVERED); + } + } + } + } + + + /* Print out the contraints */ + if (! output_symbolic) { + (void) fprintf(fp, + "# Symbolic constraints for variable %d (Numeric form)\n", var); + (void) fprintf(fp, "# unconstrained weight = %d\n", noweight); + (void) fprintf(fp, "num_codes=%d\n", cube.part_size[var]); + for(i = 0; i < A->count; i++) { + if (weight[i] > 0) { + (void) fprintf(fp, "weight=%d: ", weight[i]); + for(j = 0; j < A->sf_size; j++) { + if (is_in_set(GETSET(A,i), j)) { + (void) fprintf(fp, " %d", j); + } + } + (void) fprintf(fp, "\n"); + } + } + } else { + (void) fprintf(fp, + "# Symbolic constraints for variable %d (Symbolic form)\n", var); + for(i = 0; i < A->count; i++) { + if (weight[i] > 0) { + (void) fprintf(fp, "# w=%d: (", weight[i]); + for(j = 0; j < A->sf_size; j++) { + if (is_in_set(GETSET(A,i), j)) { + (void) fprintf(fp, " %s", + PLA->label[cube.first_part[var]+j]); + } + } + (void) fprintf(fp, " )\n"); + } + } + FREE(weight); + } + } +} diff --git a/src/misc/espresso/dominate.c b/src/misc/espresso/dominate.c new file mode 100644 index 00000000..a930d453 --- /dev/null +++ b/src/misc/espresso/dominate.c @@ -0,0 +1,98 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +#include "mincov_int.h" + + +int +sm_row_dominance(A) +sm_matrix *A; +{ + register sm_row *prow, *prow1; + register sm_col *pcol, *least_col; + register sm_element *p, *pnext; + int rowcnt; + + rowcnt = A->nrows; + + /* Check each row against all other rows */ + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + + /* Among all columns with a 1 in this row, choose smallest */ + least_col = sm_get_col(A, prow->first_col->col_num); + for(p = prow->first_col->next_col; p != 0; p = p->next_col) { + pcol = sm_get_col(A, p->col_num); + if (pcol->length < least_col->length) { + least_col = pcol; + } + } + + /* Only check for containment against rows in this column */ + for(p = least_col->first_row; p != 0; p = pnext) { + pnext = p->next_row; + + prow1 = sm_get_row(A, p->row_num); + if ((prow1->length > prow->length) || + (prow1->length == prow->length && + prow1->row_num > prow->row_num)) { + if (sm_row_contains(prow, prow1)) { + sm_delrow(A, prow1->row_num); + } + } + } + } + + return rowcnt - A->nrows; +} + +int +sm_col_dominance(A, weight) +sm_matrix *A; +int *weight; +{ + register sm_row *prow; + register sm_col *pcol, *pcol1; + register sm_element *p; + sm_row *least_row; + sm_col *next_col; + int colcnt; + + colcnt = A->ncols; + + /* Check each column against all other columns */ + for(pcol = A->first_col; pcol != 0; pcol = next_col) { + next_col = pcol->next_col; + + /* Check all rows to find the one with fewest elements */ + least_row = sm_get_row(A, pcol->first_row->row_num); + for(p = pcol->first_row->next_row; p != 0; p = p->next_row) { + prow = sm_get_row(A, p->row_num); + if (prow->length < least_row->length) { + least_row = prow; + } + } + + /* Only check for containment against columns in this row */ + for(p = least_row->first_col; p != 0; p = p->next_col) { + pcol1 = sm_get_col(A, p->col_num); + if (weight != 0 && weight[pcol1->col_num] > weight[pcol->col_num]) + continue; + if ((pcol1->length > pcol->length) || + (pcol1->length == pcol->length && + pcol1->col_num > pcol->col_num)) { + if (sm_col_contains(pcol, pcol1)) { + sm_delcol(A, pcol->col_num); + break; + } + } + } + } + + return colcnt - A->ncols; +} diff --git a/src/misc/espresso/equiv.c b/src/misc/espresso/equiv.c new file mode 100644 index 00000000..ba898a70 --- /dev/null +++ b/src/misc/espresso/equiv.c @@ -0,0 +1,94 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +#include "espresso.h" + + +find_equiv_outputs(PLA) +pPLA PLA; +{ + int i, j, ipart, jpart, some_equiv; + pcover *R, *F; + + some_equiv = FALSE; + + makeup_labels(PLA); + + F = ALLOC(pcover, cube.part_size[cube.output]); + R = ALLOC(pcover, cube.part_size[cube.output]); + + for(i = 0; i < cube.part_size[cube.output]; i++) { + ipart = cube.first_part[cube.output] + i; + R[i] = cof_output(PLA->R, ipart); + F[i] = complement(cube1list(R[i])); + } + + for(i = 0; i < cube.part_size[cube.output]-1; i++) { + for(j = i+1; j < cube.part_size[cube.output]; j++) { + ipart = cube.first_part[cube.output] + i; + jpart = cube.first_part[cube.output] + j; + + if (check_equiv(F[i], F[j])) { + (void) printf("# Outputs %d and %d (%s and %s) are equivalent\n", + i, j, PLA->label[ipart], PLA->label[jpart]); + some_equiv = TRUE; + } else if (check_equiv(F[i], R[j])) { + (void) printf("# Outputs %d and NOT %d (%s and %s) are equivalent\n", + i, j, PLA->label[ipart], PLA->label[jpart]); + some_equiv = TRUE; + } else if (check_equiv(R[i], F[j])) { + (void) printf("# Outputs NOT %d and %d (%s and %s) are equivalent\n", + i, j, PLA->label[ipart], PLA->label[jpart]); + some_equiv = TRUE; + } else if (check_equiv(R[i], R[j])) { + (void) printf("# Outputs NOT %d and NOT %d (%s and %s) are equivalent\n", + i, j, PLA->label[ipart], PLA->label[jpart]); + some_equiv = TRUE; + } + } + } + + if (! some_equiv) { + (void) printf("# No outputs are equivalent\n"); + } + + for(i = 0; i < cube.part_size[cube.output]; i++) { + free_cover(F[i]); + free_cover(R[i]); + } + FREE(F); + FREE(R); +} + + + +int check_equiv(f1, f2) +pcover f1, f2; +{ + register pcube *f1list, *f2list; + register pcube p, last; + + f1list = cube1list(f1); + foreach_set(f2, last, p) { + if (! cube_is_covered(f1list, p)) { + return FALSE; + } + } + free_cubelist(f1list); + + f2list = cube1list(f2); + foreach_set(f1, last, p) { + if (! cube_is_covered(f2list, p)) { + return FALSE; + } + } + free_cubelist(f2list); + + return TRUE; +} diff --git a/src/misc/espresso/espresso.c b/src/misc/espresso/espresso.c new file mode 100644 index 00000000..8f05d43f --- /dev/null +++ b/src/misc/espresso/espresso.c @@ -0,0 +1,139 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +/* + * Module: espresso.c + * Purpose: The main espresso algorithm + * + * Returns a minimized version of the ON-set of a function + * + * The following global variables affect the operation of Espresso: + * + * MISCELLANEOUS: + * trace + * print trace information as the minimization progresses + * + * remove_essential + * remove essential primes + * + * single_expand + * if true, stop after first expand/irredundant + * + * LAST_GASP or SUPER_GASP strategy: + * use_super_gasp + * uses the super_gasp strategy rather than last_gasp + * + * SETUP strategy: + * recompute_onset + * recompute onset using the complement before starting + * + * unwrap_onset + * unwrap the function output part before first expand + * + * MAKE_SPARSE strategy: + * force_irredundant + * iterates make_sparse to force a minimal solution (used + * indirectly by make_sparse) + * + * skip_make_sparse + * skip the make_sparse step (used by opo only) + */ + +#include "espresso.h" + +pcover espresso(F, D1, R) +pcover F, D1, R; +{ + pcover E, D, Fsave; + pset last, p; + cost_t cost, best_cost; + +begin: + Fsave = sf_save(F); /* save original function */ + D = sf_save(D1); /* make a scratch copy of D */ + + /* Setup has always been a problem */ + if (recompute_onset) { + EXEC(E = simplify(cube1list(F)), "SIMPLIFY ", E); + free_cover(F); + F = E; + } + cover_cost(F, &cost); + if (unwrap_onset && (cube.part_size[cube.num_vars - 1] > 1) + && (cost.out != cost.cubes*cube.part_size[cube.num_vars-1]) + && (cost.out < 5000)) + EXEC(F = sf_contain(unravel(F, cube.num_vars - 1)), "SETUP ", F); + + /* Initial expand and irredundant */ + foreach_set(F, last, p) { + RESET(p, PRIME); + } + EXECUTE(F = expand(F, R, FALSE), EXPAND_TIME, F, cost); + EXECUTE(F = irredundant(F, D), IRRED_TIME, F, cost); + + if (! single_expand) { + if (remove_essential) { + EXECUTE(E = essential(&F, &D), ESSEN_TIME, E, cost); + } else { + E = new_cover(0); + } + + cover_cost(F, &cost); + do { + + /* Repeat inner loop until solution becomes "stable" */ + do { + copy_cost(&cost, &best_cost); + EXECUTE(F = reduce(F, D), REDUCE_TIME, F, cost); + EXECUTE(F = expand(F, R, FALSE), EXPAND_TIME, F, cost); + EXECUTE(F = irredundant(F, D), IRRED_TIME, F, cost); + } while (cost.cubes < best_cost.cubes); + + /* Perturb solution to see if we can continue to iterate */ + copy_cost(&cost, &best_cost); + if (use_super_gasp) { + F = super_gasp(F, D, R, &cost); + if (cost.cubes >= best_cost.cubes) + break; + } else { + F = last_gasp(F, D, R, &cost); + } + + } while (cost.cubes < best_cost.cubes || + (cost.cubes == best_cost.cubes && cost.total < best_cost.total)); + + /* Append the essential cubes to F */ + F = sf_append(F, E); /* disposes of E */ + if (trace) size_stamp(F, "ADJUST "); + } + + /* Free the D which we used */ + free_cover(D); + + /* Attempt to make the PLA matrix sparse */ + if (! skip_make_sparse) { + F = make_sparse(F, D1, R); + } + + /* + * Check to make sure function is actually smaller !! + * This can only happen because of the initial unravel. If we fail, + * then run the whole thing again without the unravel. + */ + if (Fsave->count < F->count) { + free_cover(F); + F = Fsave; + unwrap_onset = FALSE; + goto begin; + } else { + free_cover(Fsave); + } + + return F; +} diff --git a/src/misc/espresso/espresso.h b/src/misc/espresso/espresso.h new file mode 100644 index 00000000..1c7a8646 --- /dev/null +++ b/src/misc/espresso/espresso.h @@ -0,0 +1,782 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +/* + * espresso.h -- header file for Espresso-mv + */ + +//#include "port.h" +//#include "utility.h" +#include "sparse.h" +#include "mincov.h" + +#include "util_hack.h" // added + +#define ptime() util_cpu_time() +#define print_time(t) util_print_time(t) + +#ifdef IBM_WATC +#define void int +#include "short.h" +#endif + +#ifdef IBMPC /* set default options for IBM/PC */ +#define NO_INLINE +#define BPI 16 +#endif + +/*-----THIS USED TO BE set.h----- */ + +/* + * set.h -- definitions for packed arrays of bits + * + * This header file describes the data structures which comprise a + * facility for efficiently implementing packed arrays of bits + * (otherwise known as sets, cf. Pascal). + * + * A set is a vector of bits and is implemented here as an array of + * unsigned integers. The low order bits of set[0] give the index of + * the last word of set data. The higher order bits of set[0] are + * used to store data associated with the set. The set data is + * contained in elements set[1] ... set[LOOP(set)] as a packed bit + * array. + * + * A family of sets is a two-dimensional matrix of bits and is + * implemented with the data type "set_family". + * + * BPI == 32 and BPI == 16 have been tested and work. + */ + + +/* Define host machine characteristics of "unsigned int" */ +#ifndef BPI +#define BPI 32 /* # bits per integer */ +#endif + +#if BPI == 32 +#define LOGBPI 5 /* log(BPI)/log(2) */ +#else +#define LOGBPI 4 /* log(BPI)/log(2) */ +#endif + +/* Define the set type */ +typedef unsigned int *pset; + +/* Define the set family type -- an array of sets */ +typedef struct set_family { + int wsize; /* Size of each set in 'ints' */ + int sf_size; /* User declared set size */ + int capacity; /* Number of sets allocated */ + int count; /* The number of sets in the family */ + int active_count; /* Number of "active" sets */ + pset data; /* Pointer to the set data */ + struct set_family *next; /* For garbage collection */ +} set_family_t, *pset_family; + +/* Macros to set and test single elements */ +#define WHICH_WORD(element) (((element) >> LOGBPI) + 1) +#define WHICH_BIT(element) ((element) & (BPI-1)) + +/* # of ints needed to allocate a set with "size" elements */ +#if BPI == 32 +#define SET_SIZE(size) ((size) <= BPI ? 2 : (WHICH_WORD((size)-1) + 1)) +#else +#define SET_SIZE(size) ((size) <= BPI ? 3 : (WHICH_WORD((size)-1) + 2)) +#endif + +/* + * Three fields are maintained in the first word of the set + * LOOP is the index of the last word used for set data + * LOOPCOPY is the index of the last word in the set + * SIZE is available for general use (e.g., recording # elements in set) + * NELEM retrieves the number of elements in the set + */ +#define LOOP(set) (set[0] & 0x03ff) +#define PUTLOOP(set, i) (set[0] &= ~0x03ff, set[0] |= (i)) +#if BPI == 32 +#define LOOPCOPY(set) LOOP(set) +#define SIZE(set) (set[0] >> 16) +#define PUTSIZE(set, size) (set[0] &= 0xffff, set[0] |= ((size) << 16)) +#else +#define LOOPCOPY(set) (LOOP(set) + 1) +#define SIZE(set) (set[LOOP(set)+1]) +#define PUTSIZE(set, size) ((set[LOOP(set)+1]) = (size)) +#endif + +#define NELEM(set) (BPI * LOOP(set)) +#define LOOPINIT(size) ((size <= BPI) ? 1 : WHICH_WORD((size)-1)) + +/* + * FLAGS store general information about the set + */ +#define SET(set, flag) (set[0] |= (flag)) +#define RESET(set, flag) (set[0] &= ~ (flag)) +#define TESTP(set, flag) (set[0] & (flag)) + +/* Flag definitions are ... */ +#define PRIME 0x8000 /* cube is prime */ +#define NONESSEN 0x4000 /* cube cannot be essential prime */ +#define ACTIVE 0x2000 /* cube is still active */ +#define REDUND 0x1000 /* cube is redundant(at this point) */ +#define COVERED 0x0800 /* cube has been covered */ +#define RELESSEN 0x0400 /* cube is relatively essential */ + +/* Most efficient way to look at all members of a set family */ +#define foreach_set(R, last, p)\ + for(p=R->data,last=p+R->count*R->wsize;pwsize) +#define foreach_remaining_set(R, last, pfirst, p)\ + for(p=pfirst+R->wsize,last=R->data+R->count*R->wsize;pwsize) +#define foreach_active_set(R, last, p)\ + foreach_set(R,last,p) if (TESTP(p, ACTIVE)) + +/* Another way that also keeps the index of the current set member in i */ +#define foreachi_set(R, i, p)\ + for(p=R->data,i=0;icount;p+=R->wsize,i++) +#define foreachi_active_set(R, i, p)\ + foreachi_set(R,i,p) if (TESTP(p, ACTIVE)) + +/* Looping over all elements in a set: + * foreach_set_element(pset p, int i, unsigned val, int base) { + * . + * . + * . + * } + */ +#define foreach_set_element(p, i, val, base) \ + for(i = LOOP(p); i > 0; ) \ + for(val = p[i], base = --i << LOGBPI; val != 0; base++, val >>= 1) \ + if (val & 1) + +/* Return a pointer to a given member of a set family */ +#define GETSET(family, index) ((family)->data + (family)->wsize * (index)) + +/* Allocate and deallocate sets */ +#define set_new(size) set_clear(ALLOC(unsigned int, SET_SIZE(size)), size) +#define set_full(size) set_fill(ALLOC(unsigned int, SET_SIZE(size)), size) +#define set_save(r) set_copy(ALLOC(unsigned int, SET_SIZE(NELEM(r))), r) +#define set_free(r) FREE(r) + +/* Check for set membership, remove set element and insert set element */ +#define is_in_set(set, e) (set[WHICH_WORD(e)] & (1 << WHICH_BIT(e))) +#define set_remove(set, e) (set[WHICH_WORD(e)] &= ~ (1 << WHICH_BIT(e))) +#define set_insert(set, e) (set[WHICH_WORD(e)] |= 1 << WHICH_BIT(e)) + +/* Inline code substitution for those places that REALLY need it on a VAX */ +#ifdef NO_INLINE +#define INLINEset_copy(r, a) (void) set_copy(r,a) +#define INLINEset_clear(r, size) (void) set_clear(r, size) +#define INLINEset_fill(r, size) (void) set_fill(r, size) +#define INLINEset_and(r, a, b) (void) set_and(r, a, b) +#define INLINEset_or(r, a, b) (void) set_or(r, a, b) +#define INLINEset_diff(r, a, b) (void) set_diff(r, a, b) +#define INLINEset_ndiff(r, a, b, f) (void) set_ndiff(r, a, b, f) +#define INLINEset_xor(r, a, b) (void) set_xor(r, a, b) +#define INLINEset_xnor(r, a, b, f) (void) set_xnor(r, a, b, f) +#define INLINEset_merge(r, a, b, mask) (void) set_merge(r, a, b, mask) +#define INLINEsetp_implies(a, b, when_false) \ + if (! setp_implies(a,b)) when_false +#define INLINEsetp_disjoint(a, b, when_false) \ + if (! setp_disjoint(a,b)) when_false +#define INLINEsetp_equal(a, b, when_false) \ + if (! setp_equal(a,b)) when_false + +#else + +#define INLINEset_copy(r, a)\ + {register int i_=LOOPCOPY(a); do r[i_]=a[i_]; while (--i_>=0);} +#define INLINEset_clear(r, size)\ + {register int i_=LOOPINIT(size); *r=i_; do r[i_] = 0; while (--i_ > 0);} +#define INLINEset_fill(r, size)\ + {register int i_=LOOPINIT(size); *r=i_; \ + r[i_]=((unsigned int)(~0))>>(i_*BPI-size); while(--i_>0) r[i_]=~0;} +#define INLINEset_and(r, a, b)\ + {register int i_=LOOP(a); PUTLOOP(r,i_);\ + do r[i_] = a[i_] & b[i_]; while (--i_>0);} +#define INLINEset_or(r, a, b)\ + {register int i_=LOOP(a); PUTLOOP(r,i_);\ + do r[i_] = a[i_] | b[i_]; while (--i_>0);} +#define INLINEset_diff(r, a, b)\ + {register int i_=LOOP(a); PUTLOOP(r,i_);\ + do r[i_] = a[i_] & ~ b[i_]; while (--i_>0);} +#define INLINEset_ndiff(r, a, b, fullset)\ + {register int i_=LOOP(a); PUTLOOP(r,i_);\ + do r[i_] = fullset[i_] & (a[i_] | ~ b[i_]); while (--i_>0);} +#ifdef IBM_WATC +#define INLINEset_xor(r, a, b) (void) set_xor(r, a, b) +#define INLINEset_xnor(r, a, b, f) (void) set_xnor(r, a, b, f) +#else +#define INLINEset_xor(r, a, b)\ + {register int i_=LOOP(a); PUTLOOP(r,i_);\ + do r[i_] = a[i_] ^ b[i_]; while (--i_>0);} +#define INLINEset_xnor(r, a, b, fullset)\ + {register int i_=LOOP(a); PUTLOOP(r,i_);\ + do r[i_] = fullset[i_] & ~ (a[i_] ^ b[i_]); while (--i_>0);} +#endif +#define INLINEset_merge(r, a, b, mask)\ + {register int i_=LOOP(a); PUTLOOP(r,i_);\ + do r[i_] = (a[i_]&mask[i_]) | (b[i_]&~mask[i_]); while (--i_>0);} +#define INLINEsetp_implies(a, b, when_false)\ + {register int i_=LOOP(a); do if (a[i_]&~b[i_]) break; while (--i_>0);\ + if (i_ != 0) when_false;} +#define INLINEsetp_disjoint(a, b, when_false)\ + {register int i_=LOOP(a); do if (a[i_]&b[i_]) break; while (--i_>0);\ + if (i_ != 0) when_false;} +#define INLINEsetp_equal(a, b, when_false)\ + {register int i_=LOOP(a); do if (a[i_]!=b[i_]) break; while (--i_>0);\ + if (i_ != 0) when_false;} + +#endif + +#if BPI == 32 +#define count_ones(v)\ + (bit_count[v & 255] + bit_count[(v >> 8) & 255]\ + + bit_count[(v >> 16) & 255] + bit_count[(v >> 24) & 255]) +#else +#define count_ones(v) (bit_count[v & 255] + bit_count[(v >> 8) & 255]) +#endif + +/* Table for efficient bit counting */ +extern int bit_count[256]; +/*----- END OF set.h ----- */ + + +/* Define a boolean type */ +#define bool int +#define FALSE 0 +#define TRUE 1 +#define MAYBE 2 +#define print_bool(x) ((x) == 0 ? "FALSE" : ((x) == 1 ? "TRUE" : "MAYBE")) + +/* Map many cube/cover types/routines into equivalent set types/routines */ +#define pcube pset +#define new_cube() set_new(cube.size) +#define free_cube(r) set_free(r) +#define pcover pset_family +#define new_cover(i) sf_new(i, cube.size) +#define free_cover(r) sf_free(r) +#define free_cubelist(T) FREE(T[0]); FREE(T); + + +/* cost_t describes the cost of a cover */ +typedef struct cost_struct { + int cubes; /* number of cubes in the cover */ + int in; /* transistor count, binary-valued variables */ + int out; /* transistor count, output part */ + int mv; /* transistor count, multiple-valued vars */ + int total; /* total number of transistors */ + int primes; /* number of prime cubes */ +} cost_t, *pcost; + + +/* pair_t describes bit-paired variables */ +typedef struct pair_struct { + int cnt; + int *var1; + int *var2; +} pair_t, *ppair; + + +/* symbolic_list_t describes a single ".symbolic" line */ +typedef struct symbolic_list_struct { + int variable; + int pos; + struct symbolic_list_struct *next; +} symbolic_list_t; + + +/* symbolic_list_t describes a single ".symbolic" line */ +typedef struct symbolic_label_struct { + char *label; + struct symbolic_label_struct *next; +} symbolic_label_t; + + +/* symbolic_t describes a linked list of ".symbolic" lines */ +typedef struct symbolic_struct { + symbolic_list_t *symbolic_list; /* linked list of items */ + int symbolic_list_length; /* length of symbolic_list list */ + symbolic_label_t *symbolic_label; /* linked list of new names */ + int symbolic_label_length; /* length of symbolic_label list */ + struct symbolic_struct *next; +} symbolic_t; + + +/* PLA_t stores the logical representation of a PLA */ +typedef struct { + pcover F, D, R; /* on-set, off-set and dc-set */ + char *filename; /* filename */ + int pla_type; /* logical PLA format */ + pcube phase; /* phase to split into on-set and off-set */ + ppair pair; /* how to pair variables */ + char **label; /* labels for the columns */ + symbolic_t *symbolic; /* allow binary->symbolic mapping */ + symbolic_t *symbolic_output;/* allow symbolic output mapping */ +} PLA_t, *pPLA; + +#define equal(a,b) (strcmp(a,b) == 0) + +/* This is a hack which I wish I hadn't done, but too painful to change */ +#define CUBELISTSIZE(T) (((pcube *) T[1] - T) - 3) + +/* For documentation purposes */ +#define IN +#define OUT +#define INOUT + +/* The pla_type field describes the input and output format of the PLA */ +#define F_type 1 +#define D_type 2 +#define R_type 4 +#define PLEASURE_type 8 /* output format */ +#define EQNTOTT_type 16 /* output format algebraic eqns */ +#define KISS_type 128 /* output format kiss */ +#define CONSTRAINTS_type 256 /* output the constraints (numeric) */ +#define SYMBOLIC_CONSTRAINTS_type 512 /* output the constraints (symbolic) */ +#define FD_type (F_type | D_type) +#define FR_type (F_type | R_type) +#define DR_type (D_type | R_type) +#define FDR_type (F_type | D_type | R_type) + +/* Definitions for the debug variable */ +#define COMPL 0x0001 +#define ESSEN 0x0002 +#define EXPAND 0x0004 +#define EXPAND1 0x0008 +#define GASP 0x0010 +#define IRRED 0x0020 +#define REDUCE 0x0040 +#define REDUCE1 0x0080 +#define SPARSE 0x0100 +#define TAUT 0x0200 +#define EXACT 0x0400 +#define MINCOV 0x0800 +#define MINCOV1 0x1000 +#define SHARP 0x2000 +#define IRRED1 0x4000 + +#define VERSION\ + "UC Berkeley, Espresso Version #2.3, Release date 01/31/88" + +/* Define constants used for recording program statistics */ +#define TIME_COUNT 16 +#define READ_TIME 0 +#define COMPL_TIME 1 +#define ONSET_TIME 2 +#define ESSEN_TIME 3 +#define EXPAND_TIME 4 +#define IRRED_TIME 5 +#define REDUCE_TIME 6 +#define GEXPAND_TIME 7 +#define GIRRED_TIME 8 +#define GREDUCE_TIME 9 +#define PRIMES_TIME 10 +#define MINCOV_TIME 11 +#define MV_REDUCE_TIME 12 +#define RAISE_IN_TIME 13 +#define VERIFY_TIME 14 +#define WRITE_TIME 15 + + +/* For those who like to think about PLAs, macros to get at inputs/outputs */ +#define NUMINPUTS cube.num_binary_vars +#define NUMOUTPUTS cube.part_size[cube.num_vars - 1] + +#define POSITIVE_PHASE(pos)\ + (is_in_set(PLA->phase, cube.first_part[cube.output]+pos) != 0) + +#define INLABEL(var) PLA->label[cube.first_part[var] + 1] +#define OUTLABEL(pos) PLA->label[cube.first_part[cube.output] + pos] + +#define GETINPUT(c, pos)\ + ((c[WHICH_WORD(2*pos)] >> WHICH_BIT(2*pos)) & 3) +#define GETOUTPUT(c, pos)\ + (is_in_set(c, cube.first_part[cube.output] + pos) != 0) + +#define PUTINPUT(c, pos, value)\ + c[WHICH_WORD(2*pos)] = (c[WHICH_WORD(2*pos)] & ~(3 << WHICH_BIT(2*pos)))\ + | (value << WHICH_BIT(2*pos)) +#define PUTOUTPUT(c, pos, value)\ + c[WHICH_WORD(pos)] = (c[WHICH_WORD(pos)] & ~(1 << WHICH_BIT(pos)))\ + | (value << WHICH_BIT(pos)) + +#define TWO 3 +#define DASH 3 +#define ONE 2 +#define ZERO 1 + + +#define EXEC(fct, name, S)\ + {long t=ptime();fct;if(trace)print_trace(S,name,ptime()-t);} +#define EXEC_S(fct, name, S)\ + {long t=ptime();fct;if(summary)print_trace(S,name,ptime()-t);} +#define EXECUTE(fct,i,S,cost)\ + {long t=ptime();fct;totals(t,i,S,&(cost));} + +/* + * Global Variable Declarations + */ + +extern unsigned int debug; /* debug parameter */ +extern bool verbose_debug; /* -v: whether to print a lot */ +extern char *total_name[TIME_COUNT]; /* basic function names */ +extern long total_time[TIME_COUNT]; /* time spent in basic fcts */ +extern int total_calls[TIME_COUNT]; /* # calls to each fct */ + +extern bool echo_comments; /* turned off by -eat option */ +extern bool echo_unknown_commands; /* always true ?? */ +extern bool force_irredundant; /* -nirr command line option */ +extern bool skip_make_sparse; +extern bool kiss; /* -kiss command line option */ +extern bool pos; /* -pos command line option */ +extern bool print_solution; /* -x command line option */ +extern bool recompute_onset; /* -onset command line option */ +extern bool remove_essential; /* -ness command line option */ +extern bool single_expand; /* -fast command line option */ +extern bool summary; /* -s command line option */ +extern bool trace; /* -t command line option */ +extern bool unwrap_onset; /* -nunwrap command line option */ +extern bool use_random_order; /* -random command line option */ +extern bool use_super_gasp; /* -strong command line option */ +extern char *filename; /* filename PLA was read from */ +extern bool debug_exact_minimization; /* dumps info for -do exact */ + + +/* + * pla_types are the input and output types for reading/writing a PLA + */ +struct pla_types_struct { + char *key; + int value; +}; + + +/* + * The cube structure is a global structure which contains information + * on how a set maps into a cube -- i.e., number of parts per variable, + * number of variables, etc. Also, many fields are pre-computed to + * speed up various primitive operations. + */ +#define CUBE_TEMP 10 + +struct cube_struct { + int size; /* set size of a cube */ + int num_vars; /* number of variables in a cube */ + int num_binary_vars; /* number of binary variables */ + int *first_part; /* first element of each variable */ + int *last_part; /* first element of each variable */ + int *part_size; /* number of elements in each variable */ + int *first_word; /* first word for each variable */ + int *last_word; /* last word for each variable */ + pset binary_mask; /* Mask to extract binary variables */ + pset mv_mask; /* mask to get mv parts */ + pset *var_mask; /* mask to extract a variable */ + pset *temp; /* an array of temporary sets */ + pset fullset; /* a full cube */ + pset emptyset; /* an empty cube */ + unsigned int inmask; /* mask to get odd word of binary part */ + int inword; /* which word number for above */ + int *sparse; /* should this variable be sparse? */ + int num_mv_vars; /* number of multiple-valued variables */ + int output; /* which variable is "output" (-1 if none) */ +}; + +struct cdata_struct { + int *part_zeros; /* count of zeros for each element */ + int *var_zeros; /* count of zeros for each variable */ + int *parts_active; /* number of "active" parts for each var */ + bool *is_unate; /* indicates given var is unate */ + int vars_active; /* number of "active" variables */ + int vars_unate; /* number of unate variables */ + int best; /* best "binate" variable */ +}; + + +extern struct pla_types_struct pla_types[]; +extern struct cube_struct cube, temp_cube_save; +extern struct cdata_struct cdata, temp_cdata_save; + +#ifdef lint +#define DISJOINT 0x5555 +#else +#if BPI == 32 +#define DISJOINT 0x55555555 +#else +#define DISJOINT 0x5555 +#endif +#endif + +/* function declarations */ + +/* cofactor.c */ extern int binate_split_select(); +/* cofactor.c */ extern pcover cubeunlist(); +/* cofactor.c */ extern pcube *cofactor(); +/* cofactor.c */ extern pcube *cube1list(); +/* cofactor.c */ extern pcube *cube2list(); +/* cofactor.c */ extern pcube *cube3list(); +/* cofactor.c */ extern pcube *scofactor(); +/* cofactor.c */ extern void massive_count(); +/* compl.c */ extern pcover complement(); +/* compl.c */ extern pcover simplify(); +/* compl.c */ extern void simp_comp(); +/* contain.c */ extern int d1_rm_equal(); +/* contain.c */ extern int rm2_contain(); +/* contain.c */ extern int rm2_equal(); +/* contain.c */ extern int rm_contain(); +/* contain.c */ extern int rm_equal(); +/* contain.c */ extern int rm_rev_contain(); +/* contain.c */ extern pset *sf_list(); +/* contain.c */ extern pset *sf_sort(); +/* contain.c */ extern pset_family d1merge(); +/* contain.c */ extern pset_family dist_merge(); +/* contain.c */ extern pset_family sf_contain(); +/* contain.c */ extern pset_family sf_dupl(); +/* contain.c */ extern pset_family sf_ind_contain(); +/* contain.c */ extern pset_family sf_ind_unlist(); +/* contain.c */ extern pset_family sf_merge(); +/* contain.c */ extern pset_family sf_rev_contain(); +/* contain.c */ extern pset_family sf_union(); +/* contain.c */ extern pset_family sf_unlist(); +/* cubestr.c */ extern void cube_setup(); +/* cubestr.c */ extern void restore_cube_struct(); +/* cubestr.c */ extern void save_cube_struct(); +/* cubestr.c */ extern void setdown_cube(); +/* cvrin.c */ extern PLA_labels(); +/* cvrin.c */ extern char *get_word(); +/* cvrin.c */ extern int label_index(); +/* cvrin.c */ extern int read_pla(); +/* cvrin.c */ extern int read_symbolic(); +/* cvrin.c */ extern pPLA new_PLA(); +/* cvrin.c */ extern void PLA_summary(); +/* cvrin.c */ extern void free_PLA(); +/* cvrin.c */ extern void parse_pla(); +/* cvrin.c */ extern void read_cube(); +/* cvrin.c */ extern void skip_line(); +/* cvrm.c */ extern foreach_output_function(); +/* cvrm.c */ extern int cubelist_partition(); +/* cvrm.c */ extern int so_both_do_espresso(); +/* cvrm.c */ extern int so_both_do_exact(); +/* cvrm.c */ extern int so_both_save(); +/* cvrm.c */ extern int so_do_espresso(); +/* cvrm.c */ extern int so_do_exact(); +/* cvrm.c */ extern int so_save(); +/* cvrm.c */ extern pcover cof_output(); +/* cvrm.c */ extern pcover lex_sort(); +/* cvrm.c */ extern pcover mini_sort(); +/* cvrm.c */ extern pcover random_order(); +/* cvrm.c */ extern pcover size_sort(); +/* cvrm.c */ extern pcover sort_reduce(); +/* cvrm.c */ extern pcover uncof_output(); +/* cvrm.c */ extern pcover unravel(); +/* cvrm.c */ extern pcover unravel_range(); +/* cvrm.c */ extern void so_both_espresso(); +/* cvrm.c */ extern void so_espresso(); +/* cvrmisc.c */ extern char *fmt_cost(); +/* cvrmisc.c */ extern char *print_cost(); +/* cvrmisc.c */ extern char *strsav(); +/* cvrmisc.c */ extern void copy_cost(); +/* cvrmisc.c */ extern void cover_cost(); +/* cvrmisc.c */ extern void fatal(); +/* cvrmisc.c */ extern void print_trace(); +/* cvrmisc.c */ extern void size_stamp(); +/* cvrmisc.c */ extern void totals(); +/* cvrout.c */ extern char *fmt_cube(); +/* cvrout.c */ extern char *fmt_expanded_cube(); +/* cvrout.c */ extern char *pc1(); +/* cvrout.c */ extern char *pc2(); +/* cvrout.c */ extern char *pc3(); +/* cvrout.c */ extern int makeup_labels(); +/* cvrout.c */ extern kiss_output(); +/* cvrout.c */ extern kiss_print_cube(); +/* cvrout.c */ extern output_symbolic_constraints(); +/* cvrout.c */ extern void cprint(); +/* cvrout.c */ extern void debug1_print(); +/* cvrout.c */ extern void debug_print(); +/* cvrout.c */ extern void eqn_output(); +/* cvrout.c */ extern void fpr_header(); +/* cvrout.c */ extern void fprint_pla(); +/* cvrout.c */ extern void pls_group(); +/* cvrout.c */ extern void pls_label(); +/* cvrout.c */ extern void pls_output(); +/* cvrout.c */ extern void print_cube(); +/* cvrout.c */ extern void print_expanded_cube(); +/* cvrout.c */ extern void sf_debug_print(); +/* equiv.c */ extern find_equiv_outputs(); +/* equiv.c */ extern int check_equiv(); +/* espresso.c */ extern pcover espresso(); +/* essen.c */ extern bool essen_cube(); +/* essen.c */ extern pcover cb_consensus(); +/* essen.c */ extern pcover cb_consensus_dist0(); +/* essen.c */ extern pcover essential(); +/* exact.c */ extern pcover minimize_exact(); +/* exact.c */ extern pcover minimize_exact_literals(); +/* expand.c */ extern bool feasibly_covered(); +/* expand.c */ extern int most_frequent(); +/* expand.c */ extern pcover all_primes(); +/* expand.c */ extern pcover expand(); +/* expand.c */ extern pcover find_all_primes(); +/* expand.c */ extern void elim_lowering(); +/* expand.c */ extern void essen_parts(); +/* expand.c */ extern void essen_raising(); +/* expand.c */ extern void expand1(); +/* expand.c */ extern void mincov(); +/* expand.c */ extern void select_feasible(); +/* expand.c */ extern void setup_BB_CC(); +/* gasp.c */ extern pcover expand_gasp(); +/* gasp.c */ extern pcover irred_gasp(); +/* gasp.c */ extern pcover last_gasp(); +/* gasp.c */ extern pcover super_gasp(); +/* gasp.c */ extern void expand1_gasp(); +/* getopt.c */ extern int util_getopt(); +/* hack.c */ extern find_dc_inputs(); +/* hack.c */ extern find_inputs(); +/* hack.c */ extern form_bitvector(); +/* hack.c */ extern map_dcset(); +/* hack.c */ extern map_output_symbolic(); +/* hack.c */ extern map_symbolic(); +/* hack.c */ extern pcover map_symbolic_cover(); +/* hack.c */ extern symbolic_hack_labels(); +/* irred.c */ extern bool cube_is_covered(); +/* irred.c */ extern bool taut_special_cases(); +/* irred.c */ extern bool tautology(); +/* irred.c */ extern pcover irredundant(); +/* irred.c */ extern void mark_irredundant(); +/* irred.c */ extern void irred_split_cover(); +/* irred.c */ extern sm_matrix *irred_derive_table(); +/* map.c */ extern pset minterms(); +/* map.c */ extern void explode(); +/* map.c */ extern void map(); +/* opo.c */ extern output_phase_setup(); +/* opo.c */ extern pPLA set_phase(); +/* opo.c */ extern pcover opo(); +/* opo.c */ extern pcube find_phase(); +/* opo.c */ extern pset_family find_covers(); +/* opo.c */ extern pset_family form_cover_table(); +/* opo.c */ extern pset_family opo_leaf(); +/* opo.c */ extern pset_family opo_recur(); +/* opo.c */ extern void opoall(); +/* opo.c */ extern void phase_assignment(); +/* opo.c */ extern void repeated_phase_assignment(); +/* pair.c */ extern generate_all_pairs(); +/* pair.c */ extern int **find_pairing_cost(); +/* pair.c */ extern int find_best_cost(); +/* pair.c */ extern int greedy_best_cost(); +/* pair.c */ extern int minimize_pair(); +/* pair.c */ extern int pair_free(); +/* pair.c */ extern pair_all(); +/* pair.c */ extern pcover delvar(); +/* pair.c */ extern pcover pairvar(); +/* pair.c */ extern ppair pair_best_cost(); +/* pair.c */ extern ppair pair_new(); +/* pair.c */ extern ppair pair_save(); +/* pair.c */ extern print_pair(); +/* pair.c */ extern void find_optimal_pairing(); +/* pair.c */ extern void set_pair(); +/* pair.c */ extern void set_pair1(); +/* primes.c */ extern pcover primes_consensus(); +/* reduce.c */ extern bool sccc_special_cases(); +/* reduce.c */ extern pcover reduce(); +/* reduce.c */ extern pcube reduce_cube(); +/* reduce.c */ extern pcube sccc(); +/* reduce.c */ extern pcube sccc_cube(); +/* reduce.c */ extern pcube sccc_merge(); +/* set.c */ extern bool set_andp(); +/* set.c */ extern bool set_orp(); +/* set.c */ extern bool setp_disjoint(); +/* set.c */ extern bool setp_empty(); +/* set.c */ extern bool setp_equal(); +/* set.c */ extern bool setp_full(); +/* set.c */ extern bool setp_implies(); +/* set.c */ extern char *pbv1(); +/* set.c */ extern char *ps1(); +/* set.c */ extern int *sf_count(); +/* set.c */ extern int *sf_count_restricted(); +/* set.c */ extern int bit_index(); +/* set.c */ extern int set_dist(); +/* set.c */ extern int set_ord(); +/* set.c */ extern void set_adjcnt(); +/* set.c */ extern pset set_and(); +/* set.c */ extern pset set_clear(); +/* set.c */ extern pset set_copy(); +/* set.c */ extern pset set_diff(); +/* set.c */ extern pset set_fill(); +/* set.c */ extern pset set_merge(); +/* set.c */ extern pset set_or(); +/* set.c */ extern pset set_xor(); +/* set.c */ extern pset sf_and(); +/* set.c */ extern pset sf_or(); +/* set.c */ extern pset_family sf_active(); +/* set.c */ extern pset_family sf_addcol(); +/* set.c */ extern pset_family sf_addset(); +/* set.c */ extern pset_family sf_append(); +/* set.c */ extern pset_family sf_bm_read(); +/* set.c */ extern pset_family sf_compress(); +/* set.c */ extern pset_family sf_copy(); +/* set.c */ extern pset_family sf_copy_col(); +/* set.c */ extern pset_family sf_delc(); +/* set.c */ extern pset_family sf_delcol(); +/* set.c */ extern pset_family sf_inactive(); +/* set.c */ extern pset_family sf_join(); +/* set.c */ extern pset_family sf_new(); +/* set.c */ extern pset_family sf_permute(); +/* set.c */ extern pset_family sf_read(); +/* set.c */ extern pset_family sf_save(); +/* set.c */ extern pset_family sf_transpose(); +/* set.c */ extern void set_write(); +/* set.c */ extern void sf_bm_print(); +/* set.c */ extern void sf_cleanup(); +/* set.c */ extern void sf_delset(); +/* set.c */ extern void sf_free(); +/* set.c */ extern void sf_print(); +/* set.c */ extern void sf_write(); +/* setc.c */ extern bool ccommon(); +/* setc.c */ extern bool cdist0(); +/* setc.c */ extern bool full_row(); +/* setc.c */ extern int ascend(); +/* setc.c */ extern int cactive(); +/* setc.c */ extern int cdist(); +/* setc.c */ extern int cdist01(); +/* setc.c */ extern int cvolume(); +/* setc.c */ extern int d1_order(); +/* setc.c */ extern int d1_order_size(); +/* setc.c */ extern int desc1(); +/* setc.c */ extern int descend(); +/* setc.c */ extern int lex_order(); +/* setc.c */ extern int lex_order1(); +/* setc.c */ extern pset force_lower(); +/* setc.c */ extern void consensus(); +/* sharp.c */ extern pcover cb1_dsharp(); +/* sharp.c */ extern pcover cb_dsharp(); +/* sharp.c */ extern pcover cb_recur_dsharp(); +/* sharp.c */ extern pcover cb_recur_sharp(); +/* sharp.c */ extern pcover cb_sharp(); +/* sharp.c */ extern pcover cv_dsharp(); +/* sharp.c */ extern pcover cv_intersect(); +/* sharp.c */ extern pcover cv_sharp(); +/* sharp.c */ extern pcover dsharp(); +/* sharp.c */ extern pcover make_disjoint(); +/* sharp.c */ extern pcover sharp(); +/* sminterf.c */pset do_sm_minimum_cover(); +/* sparse.c */ extern pcover make_sparse(); +/* sparse.c */ extern pcover mv_reduce(); +#if !defined(__osf__) && !defined(__STDC__) && !defined(__hpux) +/* ucbqsort.c */ extern qsort(); +#endif +/* ucbqsort.c */ extern qst(); +/* unate.c */ extern pcover find_all_minimal_covers_petrick(); +/* unate.c */ extern pcover map_cover_to_unate(); +/* unate.c */ extern pcover map_unate_to_cover(); +/* unate.c */ extern pset_family exact_minimum_cover(); +/* unate.c */ extern pset_family gen_primes(); +/* unate.c */ extern pset_family unate_compl(); +/* unate.c */ extern pset_family unate_complement(); +/* unate.c */ extern pset_family unate_intersect(); +/* verify.c */ extern PLA_permute(); +/* verify.c */ extern bool PLA_verify(); +/* verify.c */ extern bool check_consistency(); +/* verify.c */ extern bool verify(); diff --git a/src/misc/espresso/essen.c b/src/misc/espresso/essen.c new file mode 100644 index 00000000..6a46295d --- /dev/null +++ b/src/misc/espresso/essen.c @@ -0,0 +1,179 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +/* + module: essen.c + purpose: Find essential primes in a multiple-valued function +*/ + +#include "espresso.h" + +/* + essential -- return a cover consisting of the cubes of F which are + essential prime implicants (with respect to F u D); Further, remove + these cubes from the ON-set F, and add them to the OFF-set D. + + Sometimes EXPAND can determine that a cube is not an essential prime. + If so, it will set the "NONESSEN" flag in the cube. + + We count on IRREDUNDANT to have set the flag RELESSEN to indicate + that a prime was relatively essential (i.e., covers some minterm + not contained in any other prime in the current cover), or to have + reset the flag to indicate that a prime was relatively redundant + (i.e., all minterms covered by other primes in the current cover). + Of course, after executing irredundant, all of the primes in the + cover are relatively essential, but we can mark the primes which + were redundant at the start of irredundant and avoid an extra check + on these primes for essentiality. +*/ + +pcover essential(Fp, Dp) +IN pcover *Fp, *Dp; +{ + register pcube last, p; + pcover E, F = *Fp, D = *Dp; + + /* set all cubes in F active */ + (void) sf_active(F); + + /* Might as well start out with some cubes in E */ + E = new_cover(10); + + foreach_set(F, last, p) { + /* don't test a prime which EXPAND says is nonessential */ + if (! TESTP(p, NONESSEN)) { + /* only test a prime which was relatively essential */ + if (TESTP(p, RELESSEN)) { + /* Check essentiality */ + if (essen_cube(F, D, p)) { + if (debug & ESSEN) + printf("ESSENTIAL: %s\n", pc1(p)); + E = sf_addset(E, p); + RESET(p, ACTIVE); + F->active_count--; + } + } + } + } + + *Fp = sf_inactive(F); /* delete the inactive cubes from F */ + *Dp = sf_join(D, E); /* add the essentials to D */ + sf_free(D); + return E; +} + +/* + essen_cube -- check if a single cube is essential or not + + The prime c is essential iff + + consensus((F u D) # c, c) u D + + does not contain c. +*/ +bool essen_cube(F, D, c) +IN pcover F, D; +IN pcube c; +{ + pcover H, FD; + pcube *H1; + bool essen; + + /* Append F and D together, and take the sharp-consensus with c */ + FD = sf_join(F, D); + H = cb_consensus(FD, c); + free_cover(FD); + + /* Add the don't care set, and see if this covers c */ + H1 = cube2list(H, D); + essen = ! cube_is_covered(H1, c); + free_cubelist(H1); + + free_cover(H); + return essen; +} + + +/* + * cb_consensus -- compute consensus(T # c, c) + */ +pcover cb_consensus(T, c) +register pcover T; +register pcube c; +{ + register pcube temp, last, p; + register pcover R; + + R = new_cover(T->count*2); + temp = new_cube(); + foreach_set(T, last, p) { + if (p != c) { + switch (cdist01(p, c)) { + case 0: + /* distance-0 needs special care */ + R = cb_consensus_dist0(R, p, c); + break; + + case 1: + /* distance-1 is easy because no sharping required */ + consensus(temp, p, c); + R = sf_addset(R, temp); + break; + } + } + } + set_free(temp); + return R; +} + + +/* + * form the sharp-consensus for p and c when they intersect + * What we are forming is consensus(p # c, c). + */ +pcover cb_consensus_dist0(R, p, c) +pcover R; +register pcube p, c; +{ + int var; + bool got_one; + register pcube temp, mask; + register pcube p_diff_c=cube.temp[0], p_and_c=cube.temp[1]; + + /* If c contains p, then this gives us no information for essential test */ + if (setp_implies(p, c)) { + return R; + } + + /* For the multiple-valued variables */ + temp = new_cube(); + got_one = FALSE; + INLINEset_diff(p_diff_c, p, c); + INLINEset_and(p_and_c, p, c); + + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + /* Check if c(var) is contained in p(var) -- if so, no news */ + mask = cube.var_mask[var]; + if (! setp_disjoint(p_diff_c, mask)) { + INLINEset_merge(temp, c, p_and_c, mask); + R = sf_addset(R, temp); + got_one = TRUE; + } + } + + /* if no cube so far, add one for the intersection */ + if (! got_one && cube.num_binary_vars > 0) { + /* Add a single cube for the intersection of p and c */ + INLINEset_and(temp, p, c); + R = sf_addset(R, temp); + } + + set_free(temp); + return R; +} diff --git a/src/misc/espresso/exact.c b/src/misc/espresso/exact.c new file mode 100644 index 00000000..b1943636 --- /dev/null +++ b/src/misc/espresso/exact.c @@ -0,0 +1,181 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +#include "espresso.h" + + +static void dump_irredundant(); +static pcover do_minimize(); + + +/* + * minimize_exact -- main entry point for exact minimization + * + * Global flags which affect this routine are: + * + * debug + * skip_make_sparse + */ + +pcover +minimize_exact(F, D, R, exact_cover) +pcover F, D, R; +int exact_cover; +{ + return do_minimize(F, D, R, exact_cover, /*weighted*/ 0); +} + + +pcover +minimize_exact_literals(F, D, R, exact_cover) +pcover F, D, R; +int exact_cover; +{ + return do_minimize(F, D, R, exact_cover, /*weighted*/ 1); +} + + + +static pcover +do_minimize(F, D, R, exact_cover, weighted) +pcover F, D, R; +int exact_cover; +int weighted; +{ + pcover newF, E, Rt, Rp; + pset p, last; + int heur, level, *weights, i; + sm_matrix *table; + sm_row *cover; + sm_element *pe; + int debug_save = debug; + + if (debug & EXACT) { + debug |= (IRRED | MINCOV); + } +#if defined(sun) || defined(bsd4_2) /* hack ... */ + if (debug & MINCOV) { + setlinebuf(stdout); + } +#endif + level = (debug & MINCOV) ? 4 : 0; + heur = ! exact_cover; + + /* Generate all prime implicants */ + EXEC(F = primes_consensus(cube2list(F, D)), "PRIMES ", F); + + /* Setup the prime implicant table */ + EXEC(irred_split_cover(F, D, &E, &Rt, &Rp), "ESSENTIALS ", E); + EXEC(table = irred_derive_table(D, E, Rp), "PI-TABLE ", Rp); + + /* Solve either a weighted or nonweighted covering problem */ + if (weighted) { + /* correct only for all 2-valued variables */ + weights = ALLOC(int, F->count); + foreach_set(Rp, last, p) { + weights[SIZE(p)] = cube.size - set_ord(p); + /* We have added the 0's in the output part instead of the 1's. + This loop corrects the literal count. */ + for (i = cube.first_part[cube.output]; + i <= cube.last_part[cube.output]; i++) { + is_in_set(p, i) ? weights[SIZE(p)]++ : weights[SIZE(p)]--; + } + } + } else { + weights = NIL(int); + } + EXEC(cover=sm_minimum_cover(table,weights,heur,level), "MINCOV ", F); + if (weights != 0) { + FREE(weights); + } + + if (debug & EXACT) { + dump_irredundant(E, Rt, Rp, table); + } + + /* Form the result cover */ + newF = new_cover(100); + foreach_set(E, last, p) { + newF = sf_addset(newF, p); + } + sm_foreach_row_element(cover, pe) { + newF = sf_addset(newF, GETSET(F, pe->col_num)); + } + + free_cover(E); + free_cover(Rt); + free_cover(Rp); + sm_free(table); + sm_row_free(cover); + free_cover(F); + + /* Attempt to make the results more sparse */ + debug &= ~ (IRRED | SHARP | MINCOV); + if (! skip_make_sparse && R != 0) { + newF = make_sparse(newF, D, R); + } + + debug = debug_save; + return newF; +} + +static void +dump_irredundant(E, Rt, Rp, table) +pcover E, Rt, Rp; +sm_matrix *table; +{ + FILE *fp_pi_table, *fp_primes; + pPLA PLA; + pset last, p; + char *file; + + if (filename == 0 || strcmp(filename, "(stdin)") == 0) { + fp_pi_table = fp_primes = stdout; + } else { + file = ALLOC(char, strlen(filename)+20); + (void) sprintf(file, "%s.primes", filename); + if ((fp_primes = fopen(file, "w")) == NULL) { + (void) fprintf(stderr, "espresso: Unable to open %s\n", file); + fp_primes = stdout; + } + (void) sprintf(file, "%s.pi", filename); + if ((fp_pi_table = fopen(file, "w")) == NULL) { + (void) fprintf(stderr, "espresso: Unable to open %s\n", file); + fp_pi_table = stdout; + } + FREE(file); + } + + PLA = new_PLA(); + PLA_labels(PLA); + + fpr_header(fp_primes, PLA, F_type); + free_PLA(PLA); + + (void) fprintf(fp_primes, "# Essential primes are\n"); + foreach_set(E, last, p) { + (void) fprintf(fp_primes, "%s\n", pc1(p)); + } + (void) fprintf(fp_primes, "# Totally redundant primes are\n"); + foreach_set(Rt, last, p) { + (void) fprintf(fp_primes, "%s\n", pc1(p)); + } + (void) fprintf(fp_primes, "# Partially redundant primes are\n"); + foreach_set(Rp, last, p) { + (void) fprintf(fp_primes, "%s\n", pc1(p)); + } + if (fp_primes != stdout) { + (void) fclose(fp_primes); + } + + sm_write(fp_pi_table, table); + if (fp_pi_table != stdout) { + (void) fclose(fp_pi_table); + } +} diff --git a/src/misc/espresso/expand.c b/src/misc/espresso/expand.c new file mode 100644 index 00000000..2765d71c --- /dev/null +++ b/src/misc/espresso/expand.c @@ -0,0 +1,693 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +/* + module: expand.c + purpose: Perform the Espresso-II Expansion Step + + The idea is to take each nonprime cube of the on-set and expand it + into a prime implicant such that we can cover as many other cubes + of the on-set. If no cube of the on-set can be covered, then we + expand each cube into a large prime implicant by transforming the + problem into a minimum covering problem which is solved by the + heuristics of minimum_cover. + + These routines revolve around having a representation of the + OFF-set. (In contrast to the Espresso-II manuscript, we do NOT + require an "unwrapped" version of the OFF-set). + + Some conventions on variable names: + + SUPER_CUBE is the supercube of all cubes which can be covered + by an expansion of the cube being expanded + + OVEREXPANDED_CUBE is the cube which would result from expanding + all parts which can expand individually of the cube being expanded + + RAISE is the current expansion of the current cube + + FREESET is the set of parts which haven't been raised or lowered yet. + + INIT_LOWER is a set of parts to be removed from the free parts before + starting the expansion +*/ + +#include "espresso.h" + +/* + expand -- expand each nonprime cube of F into a prime implicant + + If nonsparse is true, only the non-sparse variables will be expanded; + this is done by forcing all of the sparse variables out of the free set. +*/ + +pcover expand(F, R, nonsparse) +INOUT pcover F; +IN pcover R; +IN bool nonsparse; /* expand non-sparse variables only */ +{ + register pcube last, p; + pcube RAISE, FREESET, INIT_LOWER, SUPER_CUBE, OVEREXPANDED_CUBE; + int var, num_covered; + bool change; + + /* Order the cubes according to "chewing-away from the edges" of mini */ + if (use_random_order) + F = random_order(F); + else + F = mini_sort(F, ascend); + + /* Allocate memory for variables needed by expand1() */ + RAISE = new_cube(); + FREESET = new_cube(); + INIT_LOWER = new_cube(); + SUPER_CUBE = new_cube(); + OVEREXPANDED_CUBE = new_cube(); + + /* Setup the initial lowering set (differs only for nonsparse) */ + if (nonsparse) + for(var = 0; var < cube.num_vars; var++) + if (cube.sparse[var]) + (void) set_or(INIT_LOWER, INIT_LOWER, cube.var_mask[var]); + + /* Mark all cubes as not covered, and maybe essential */ + foreach_set(F, last, p) { + RESET(p, COVERED); + RESET(p, NONESSEN); + } + + /* Try to expand each nonprime and noncovered cube */ + foreach_set(F, last, p) { + /* do not expand if PRIME or if covered by previous expansion */ + if (! TESTP(p, PRIME) && ! TESTP(p, COVERED)) { + + /* expand the cube p, result is RAISE */ + expand1(R, F, RAISE, FREESET, OVEREXPANDED_CUBE, SUPER_CUBE, + INIT_LOWER, &num_covered, p); + if (debug & EXPAND) + printf("EXPAND: %s (covered %d)\n", pc1(p), num_covered); + (void) set_copy(p, RAISE); + SET(p, PRIME); + RESET(p, COVERED); /* not really necessary */ + + /* See if we generated an inessential prime */ + if (num_covered == 0 && ! setp_equal(p, OVEREXPANDED_CUBE)) { + SET(p, NONESSEN); + } + } + } + + /* Delete any cubes of F which became covered during the expansion */ + F->active_count = 0; + change = FALSE; + foreach_set(F, last, p) { + if (TESTP(p, COVERED)) { + RESET(p, ACTIVE); + change = TRUE; + } else { + SET(p, ACTIVE); + F->active_count++; + } + } + if (change) + F = sf_inactive(F); + + free_cube(RAISE); + free_cube(FREESET); + free_cube(INIT_LOWER); + free_cube(SUPER_CUBE); + free_cube(OVEREXPANDED_CUBE); + return F; +} + +/* + expand1 -- Expand a single cube against the OFF-set +*/ +void expand1(BB, CC, RAISE, FREESET, OVEREXPANDED_CUBE, SUPER_CUBE, + INIT_LOWER, num_covered, c) +pcover BB; /* Blocking matrix (OFF-set) */ +pcover CC; /* Covering matrix (ON-set) */ +pcube RAISE; /* The current parts which have been raised */ +pcube FREESET; /* The current parts which are free */ +pcube OVEREXPANDED_CUBE; /* Overexpanded cube of c */ +pcube SUPER_CUBE; /* Supercube of all cubes of CC we cover */ +pcube INIT_LOWER; /* Parts to initially remove from FREESET */ +int *num_covered; /* Number of cubes of CC which are covered */ +pcube c; /* The cube to be expanded */ +{ + int bestindex; + + if (debug & EXPAND1) + printf("\nEXPAND1: \t%s\n", pc1(c)); + + /* initialize BB and CC */ + SET(c, PRIME); /* don't try to cover ourself */ + setup_BB_CC(BB, CC); + + /* initialize count of # cubes covered, and the supercube of them */ + *num_covered = 0; + (void) set_copy(SUPER_CUBE, c); + + /* Initialize the lowering, raising and unassigned sets */ + (void) set_copy(RAISE, c); + (void) set_diff(FREESET, cube.fullset, RAISE); + + /* If some parts are forced into lowering set, remove them */ + if (! setp_empty(INIT_LOWER)) { + (void) set_diff(FREESET, FREESET, INIT_LOWER); + elim_lowering(BB, CC, RAISE, FREESET); + } + + /* Determine what can be raised, and return the over-expanded cube */ + essen_parts(BB, CC, RAISE, FREESET); + (void) set_or(OVEREXPANDED_CUBE, RAISE, FREESET); + + /* While there are still cubes which can be covered, cover them ! */ + if (CC->active_count > 0) { + select_feasible(BB, CC, RAISE, FREESET, SUPER_CUBE, num_covered); + } + + /* While there are still cubes covered by the overexpanded cube ... */ + while (CC->active_count > 0) { + bestindex = most_frequent(CC, FREESET); + set_insert(RAISE, bestindex); + set_remove(FREESET, bestindex); + essen_parts(BB, CC, RAISE, FREESET); + } + + /* Finally, when all else fails, choose the largest possible prime */ + /* We will loop only if we decide unravelling OFF-set is too expensive */ + while (BB->active_count > 0) { + mincov(BB, RAISE, FREESET); + } + + /* Raise any remaining free coordinates */ + (void) set_or(RAISE, RAISE, FREESET); +} + +/* + essen_parts -- determine which parts are forced into the lowering + set to insure that the cube be orthognal to the OFF-set. + + If any cube of the OFF-set is distance 1 from the raising cube, + then we must lower all parts of the conflicting variable. (If the + cube is distance 0, we detect this error here.) + + If there are essentially lowered parts, we can remove from consideration + any cubes of the OFF-set which are more than distance 1 from the + overexpanded cube of RAISE. +*/ + +void essen_parts(BB, CC, RAISE, FREESET) +pcover BB, CC; +pcube RAISE, FREESET; +{ + register pcube p, r = RAISE; + pcube lastp, xlower = cube.temp[0]; + int dist; + + (void) set_copy(xlower, cube.emptyset); + + foreach_active_set(BB, lastp, p) { +#ifdef NO_INLINE + if ((dist = cdist01(p, r)) > 1) goto exit_if; +#else + {register int w,last;register unsigned int x;dist=0;if((last=cube.inword)!=-1) +{x=p[last]&r[last];if(x=~(x|x>>1)&cube.inmask)if((dist=count_ones(x))>1)goto +exit_if;for(w=1;w>1)&DISJOINT)if(dist==1||( +dist+=count_ones(x))>1)goto exit_if;}}}{register int w,var,last;register pcube +mask;for(var=cube.num_binary_vars;var1)goto exit_if;nextvar:;}} +#endif + if (dist == 0) { + fatal("ON-set and OFF-set are not orthogonal"); + } else { + (void) force_lower(xlower, p, r); + BB->active_count--; + RESET(p, ACTIVE); + } +exit_if: ; + } + + if (! setp_empty(xlower)) { + (void) set_diff(FREESET, FREESET, xlower);/* remove from free set */ + elim_lowering(BB, CC, RAISE, FREESET); + } + + if (debug & EXPAND1) + printf("ESSEN_PARTS:\tRAISE=%s FREESET=%s\n", pc1(RAISE), pc2(FREESET)); +} + +/* + essen_raising -- determine which parts may always be added to + the raising set without restricting further expansions + + General rule: if some part is not blocked by any cube of BB, then + this part can always be raised. +*/ + +void essen_raising(BB, RAISE, FREESET) +register pcover BB; +pcube RAISE, FREESET; +{ + register pcube last, p, xraise = cube.temp[0]; + + /* Form union of all cubes of BB, and then take complement wrt FREESET */ + (void) set_copy(xraise, cube.emptyset); + foreach_active_set(BB, last, p) + INLINEset_or(xraise, xraise, p); + (void) set_diff(xraise, FREESET, xraise); + + (void) set_or(RAISE, RAISE, xraise); /* add to raising set */ + (void) set_diff(FREESET, FREESET, xraise); /* remove from free set */ + + if (debug & EXPAND1) + printf("ESSEN_RAISING:\tRAISE=%s FREESET=%s\n", + pc1(RAISE), pc2(FREESET)); +} + +/* + elim_lowering -- after removing parts from FREESET, we can reduce the + size of both BB and CC. + + We mark as inactive any cube of BB which does not intersect the + overexpanded cube (i.e., RAISE + FREESET). Likewise, we remove + from CC any cube which is not covered by the overexpanded cube. +*/ + +void elim_lowering(BB, CC, RAISE, FREESET) +pcover BB, CC; +pcube RAISE, FREESET; +{ + register pcube p, r = set_or(cube.temp[0], RAISE, FREESET); + pcube last; + + /* + * Remove sets of BB which are orthogonal to future expansions + */ + foreach_active_set(BB, last, p) { +#ifdef NO_INLINE + if (! cdist0(p, r)) +#else + {register int w,lastw;register unsigned int x;if((lastw=cube.inword)!=-1){x=p[ +lastw]&r[lastw];if(~(x|x>>1)&cube.inmask)goto false;for(w=1;w>1)&DISJOINT)goto false;}}}{register int w,var,lastw;register +pcube mask;for(var=cube.num_binary_vars;varactive_count--, RESET(p, ACTIVE); + } + + + /* + * Remove sets of CC which cannot be covered by future expansions + */ + if (CC != (pcover) NULL) { + foreach_active_set(CC, last, p) { +#ifdef NO_INLINE + if (! setp_implies(p, r)) +#else + INLINEsetp_implies(p, r, /* when false => */ goto false1); + /* when true => go to end of loop */ continue; + false1: +#endif + CC->active_count--, RESET(p, ACTIVE); + } + } +} + +/* + most_frequent -- When all else fails, select a reasonable part to raise + The active cubes of CC are the cubes which are covered by the + overexpanded cube of the original cube (however, we know that none + of them can actually be covered by a feasible expansion of the + original cube). We resort to the MINI strategy of selecting to + raise the part which will cover the same part in the most cubes of CC. +*/ +int most_frequent(CC, FREESET) +pcover CC; +pcube FREESET; +{ + register int i, best_part, best_count, *count; + register pset p, last; + + /* Count occurences of each variable */ + count = ALLOC(int, cube.size); + for(i = 0; i < cube.size; i++) + count[i] = 0; + if (CC != (pcover) NULL) + foreach_active_set(CC, last, p) + set_adjcnt(p, count, 1); + + /* Now find which free part occurs most often */ + best_count = best_part = -1; + for(i = 0; i < cube.size; i++) + if (is_in_set(FREESET,i) && count[i] > best_count) { + best_part = i; + best_count = count[i]; + } + FREE(count); + + if (debug & EXPAND1) + printf("MOST_FREQUENT:\tbest=%d FREESET=%s\n", best_part, pc2(FREESET)); + return best_part; +} + +/* + setup_BB_CC -- set up the blocking and covering set families; + + Note that the blocking family is merely the set of cubes of R, and + that CC is the set of cubes of F which might possibly be covered + (i.e., nonprime cubes, and cubes not already covered) +*/ + +void setup_BB_CC(BB, CC) +register pcover BB, CC; +{ + register pcube p, last; + + /* Create the block and cover set families */ + BB->active_count = BB->count; + foreach_set(BB, last, p) + SET(p, ACTIVE); + + if (CC != (pcover) NULL) { + CC->active_count = CC->count; + foreach_set(CC, last, p) + if (TESTP(p, COVERED) || TESTP(p, PRIME)) + CC->active_count--, RESET(p, ACTIVE); + else + SET(p, ACTIVE); + } +} + +/* + select_feasible -- Determine if there are cubes which can be covered, + and if so, raise those parts necessary to cover as many as possible. + + We really don't check to maximize the number that can be covered; + instead, we check, for each fcc, how many other fcc remain fcc + after expanding to cover the fcc. (Essentially one-level lookahead). +*/ + +void select_feasible(BB, CC, RAISE, FREESET, SUPER_CUBE, num_covered) +pcover BB, CC; +pcube RAISE, FREESET, SUPER_CUBE; +int *num_covered; +{ + register pcube p, last, bestfeas, *feas; + register int i, j; + pcube *feas_new_lower; + int bestcount, bestsize, count, size, numfeas, lastfeas; + pcover new_lower; + + /* Start out with all cubes covered by the over-expanded cube as + * the "possibly" feasibly-covered cubes (pfcc) + */ + feas = ALLOC(pcube, CC->active_count); + numfeas = 0; + foreach_active_set(CC, last, p) + feas[numfeas++] = p; + + /* Setup extra cubes to record parts forced low after a covering */ + feas_new_lower = ALLOC(pcube, CC->active_count); + new_lower = new_cover(numfeas); + for(i = 0; i < numfeas; i++) + feas_new_lower[i] = GETSET(new_lower, i); + + +loop: + /* Find the essentially raised parts -- this might cover some cubes + for us, without having to find out if they are fcc or not + */ + essen_raising(BB, RAISE, FREESET); + + /* Now check all "possibly" feasibly covered cubes to check feasibility */ + lastfeas = numfeas; + numfeas = 0; + for(i = 0; i < lastfeas; i++) { + p = feas[i]; + + /* Check active because essen_parts might have removed it */ + if (TESTP(p, ACTIVE)) { + + /* See if the cube is already covered by RAISE -- + * this can happen because of essen_raising() or because of + * the previous "loop" + */ + if (setp_implies(p, RAISE)) { + (*num_covered) += 1; + (void) set_or(SUPER_CUBE, SUPER_CUBE, p); + CC->active_count--; + RESET(p, ACTIVE); + SET(p, COVERED); + /* otherwise, test if it is feasibly covered */ + } else if (feasibly_covered(BB,p,RAISE,feas_new_lower[numfeas])) { + feas[numfeas] = p; /* save the fcc */ + numfeas++; + } + } + } + if (debug & EXPAND1) + printf("SELECT_FEASIBLE: started with %d pfcc, ended with %d fcc\n", + lastfeas, numfeas); + + /* Exit here if there are no feasibly covered cubes */ + if (numfeas == 0) { + FREE(feas); + FREE(feas_new_lower); + free_cover(new_lower); + return; + } + + /* Now find which is the best feasibly covered cube */ + bestcount = 0; + bestsize = 9999; + for(i = 0; i < numfeas; i++) { + size = set_dist(feas[i], FREESET); /* # of newly raised parts */ + count = 0; /* # of other cubes which remain fcc after raising */ + +#define NEW +#ifdef NEW + for(j = 0; j < numfeas; j++) + if (setp_disjoint(feas_new_lower[i], feas[j])) + count++; +#else + for(j = 0; j < numfeas; j++) + if (setp_implies(feas[j], feas[i])) + count++; +#endif + if (count > bestcount) { + bestcount = count; + bestfeas = feas[i]; + bestsize = size; + } else if (count == bestcount && size < bestsize) { + bestfeas = feas[i]; + bestsize = size; + } + } + + /* Add the necessary parts to the raising set */ + (void) set_or(RAISE, RAISE, bestfeas); + (void) set_diff(FREESET, FREESET, RAISE); + if (debug & EXPAND1) + printf("FEASIBLE: \tRAISE=%s FREESET=%s\n", pc1(RAISE), pc2(FREESET)); + essen_parts(BB, CC, RAISE, FREESET); + goto loop; +/* NOTREACHED */ +} + +/* + feasibly_covered -- determine if the cube c is feasibly covered + (i.e., if it is possible to raise all of the necessary variables + while still insuring orthogonality with R). Also, if c is feasibly + covered, then compute the new set of parts which are forced into + the lowering set. +*/ + +bool feasibly_covered(BB, c, RAISE, new_lower) +pcover BB; +pcube c, RAISE, new_lower; +{ + register pcube p, r = set_or(cube.temp[0], RAISE, c); + int dist; + pcube lastp; + + set_copy(new_lower, cube.emptyset); + foreach_active_set(BB, lastp, p) { +#ifdef NO_INLINE + if ((dist = cdist01(p, r)) > 1) goto exit_if; +#else + {register int w,last;register unsigned int x;dist=0;if((last=cube.inword)!=-1) +{x=p[last]&r[last];if(x=~(x|x>>1)&cube.inmask)if((dist=count_ones(x))>1)goto +exit_if;for(w=1;w>1)&DISJOINT)if(dist==1||( +dist+=count_ones(x))>1)goto exit_if;}}}{register int w,var,last;register pcube +mask;for(var=cube.num_binary_vars;var1)goto exit_if;nextvar:;}} +#endif + if (dist == 0) + return FALSE; + else + (void) force_lower(new_lower, p, r); + exit_if: ; + } + return TRUE; +} + +/* + mincov -- transform the problem of expanding a cube to a maximally- + large prime implicant into the problem of selecting a minimum + cardinality cover over a family of sets. + + When we get to this point, we must unravel the remaining off-set. + This may be painful. +*/ + +void mincov(BB, RAISE, FREESET) +pcover BB; +pcube RAISE, FREESET; +{ + int expansion, nset, var, dist; + pset_family B; + register pcube xraise=cube.temp[0], xlower, p, last, plower; + +#ifdef RANDOM_MINCOV +#if defined(_POSIX_SOURCE) || defined(__SVR4) + dist = rand() % set_ord(FREESET); +#else + dist = random() % set_ord(FREESET); +#endif + for(var = 0; var < cube.size && dist >= 0; var++) { + if (is_in_set(FREESET, var)) { + dist--; + } + } + + set_insert(RAISE, var); + set_remove(FREESET, var); + (void) essen_parts(BB, /*CC*/ (pcover) NULL, RAISE, FREESET); +#else + + /* Create B which are those cubes which we must avoid intersecting */ + B = new_cover(BB->active_count); + foreach_active_set(BB, last, p) { + plower = set_copy(GETSET(B, B->count++), cube.emptyset); + (void) force_lower(plower, p, RAISE); + } + + /* Determine how many sets it will blow up into after the unravel */ + nset = 0; + foreach_set(B, last, p) { + expansion = 1; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + if ((dist=set_dist(p, cube.var_mask[var])) > 1) { + expansion *= dist; + if (expansion > 500) goto heuristic_mincov; + } + } + nset += expansion; + if (nset > 500) goto heuristic_mincov; + } + + B = unravel(B, cube.num_binary_vars); + xlower = do_sm_minimum_cover(B); + + /* Add any remaining free parts to the raising set */ + (void) set_or(RAISE, RAISE, set_diff(xraise, FREESET, xlower)); + (void) set_copy(FREESET, cube.emptyset); /* free set is empty */ + BB->active_count = 0; /* BB satisfied */ + if (debug & EXPAND1) { + printf("MINCOV: \tRAISE=%s FREESET=%s\n", pc1(RAISE), pc2(FREESET)); + } + sf_free(B); + set_free(xlower); + return; + +heuristic_mincov: + sf_free(B); + /* most_frequent will pick first free part */ + set_insert(RAISE, most_frequent(/*CC*/ (pcover) NULL, FREESET)); + (void) set_diff(FREESET, FREESET, RAISE); + essen_parts(BB, /*CC*/ (pcover) NULL, RAISE, FREESET); + return; +#endif +} + +/* + find_all_primes -- find all of the primes which cover the + currently reduced BB +*/ +pcover find_all_primes(BB, RAISE, FREESET) +pcover BB; +register pcube RAISE, FREESET; +{ + register pset last, p, plower; + pset_family B, B1; + + if (BB->active_count == 0) { + B1 = new_cover(1); + p = GETSET(B1, B1->count++); + (void) set_copy(p, RAISE); + SET(p, PRIME); + } else { + B = new_cover(BB->active_count); + foreach_active_set(BB, last, p) { + plower = set_copy(GETSET(B, B->count++), cube.emptyset); + (void) force_lower(plower, p, RAISE); + } + B = sf_rev_contain(unravel(B, cube.num_binary_vars)); + B1 = exact_minimum_cover(B); + foreach_set(B1, last, p) { + INLINEset_diff(p, FREESET, p); + INLINEset_or(p, p, RAISE); + SET(p, PRIME); + } + free_cover(B); + } + return B1; +} + +/* + all_primes -- foreach cube in F, generate all of the primes + which cover the cube. +*/ + +pcover all_primes(F, R) +pcover F, R; +{ + register pcube last, p, RAISE, FREESET; + pcover Fall_primes, B1; + + FREESET = new_cube(); + RAISE = new_cube(); + Fall_primes = new_cover(F->count); + + foreach_set(F, last, p) { + if (TESTP(p, PRIME)) { + Fall_primes = sf_addset(Fall_primes, p); + } else { + /* Setup for call to essential parts */ + (void) set_copy(RAISE, p); + (void) set_diff(FREESET, cube.fullset, RAISE); + setup_BB_CC(R, /* CC */ (pcover) NULL); + essen_parts(R, /* CC */ (pcover) NULL, RAISE, FREESET); + + /* Find all of the primes, and add them to the prime set */ + B1 = find_all_primes(R, RAISE, FREESET); + Fall_primes = sf_append(Fall_primes, B1); + } + } + + set_free(RAISE); + set_free(FREESET); + return Fall_primes; +} diff --git a/src/misc/espresso/gasp.c b/src/misc/espresso/gasp.c new file mode 100644 index 00000000..aa3254d3 --- /dev/null +++ b/src/misc/espresso/gasp.c @@ -0,0 +1,228 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +/* + module: gasp.c + + The "last_gasp" heuristic computes the reduction of each cube in + the cover (without replacement) and then performs an expansion of + these cubes. The cubes which expand to cover some other cube are + added to the original cover and irredundant finds a minimal subset. + + If one of the reduced cubes expands to cover some other reduced + cube, then the new prime thus generated is a candidate for reducing + the size of the cover. + + super_gasp is a variation on this strategy which extracts a minimal + subset from the set of all prime implicants which cover all + maximally reduced cubes. +*/ + +#include "espresso.h" + + +/* + * reduce_gasp -- compute the maximal reduction of each cube of F + * + * If a cube does not reduce, it remains prime; otherwise, it is marked + * as nonprime. If the cube is redundant (should NEVER happen here) we + * just crap out ... + * + * A cover with all of the cubes of F is returned. Those that did + * reduce are marked "NONPRIME"; those that reduced are marked "PRIME". + * The cubes are in the same order as in F. + */ +static pcover reduce_gasp(F, D) +pcover F, D; +{ + pcube p, last, cunder, *FD; + pcover G; + + G = new_cover(F->count); + FD = cube2list(F, D); + + /* Reduce cubes of F without replacement */ + foreach_set(F, last, p) { + cunder = reduce_cube(FD, p); + if (setp_empty(cunder)) { + fatal("empty reduction in reduce_gasp, shouldn't happen"); + } else if (setp_equal(cunder, p)) { + SET(cunder, PRIME); /* just to make sure */ + G = sf_addset(G, p); /* it did not reduce ... */ + } else { + RESET(cunder, PRIME); /* it reduced ... */ + G = sf_addset(G, cunder); + } + if (debug & GASP) { + printf("REDUCE_GASP: %s reduced to %s\n", pc1(p), pc2(cunder)); + } + free_cube(cunder); + } + + free_cubelist(FD); + return G; +} + +/* + * expand_gasp -- expand each nonprime cube of F into a prime implicant + * + * The gasp strategy differs in that only those cubes which expand to + * cover some other cube are saved; also, all cubes are expanded + * regardless of whether they become covered or not. + */ + +pcover expand_gasp(F, D, R, Foriginal) +INOUT pcover F; +IN pcover D; +IN pcover R; +IN pcover Foriginal; +{ + int c1index; + pcover G; + + /* Try to expand each nonprime and noncovered cube */ + G = new_cover(10); + for(c1index = 0; c1index < F->count; c1index++) { + expand1_gasp(F, D, R, Foriginal, c1index, &G); + } + G = sf_dupl(G); + G = expand(G, R, /*nonsparse*/ FALSE); /* Make them prime ! */ + return G; +} + + + +/* + * expand1 -- Expand a single cube against the OFF-set, using the gasp strategy + */ +void expand1_gasp(F, D, R, Foriginal, c1index, G) +pcover F; /* reduced cubes of ON-set */ +pcover D; /* DC-set */ +pcover R; /* OFF-set */ +pcover Foriginal; /* ON-set before reduction (same order as F) */ +int c1index; /* which index of F (or Freduced) to be checked */ +pcover *G; +{ + register int c2index; + register pcube p, last, c2under; + pcube RAISE, FREESET, temp, *FD, c2essential; + pcover F1; + + if (debug & EXPAND1) { + printf("\nEXPAND1_GASP: \t%s\n", pc1(GETSET(F, c1index))); + } + + RAISE = new_cube(); + FREESET = new_cube(); + temp = new_cube(); + + /* Initialize the OFF-set */ + R->active_count = R->count; + foreach_set(R, last, p) { + SET(p, ACTIVE); + } + /* Initialize the reduced ON-set, all nonprime cubes become active */ + F->active_count = F->count; + foreachi_set(F, c2index, c2under) { + if (c1index == c2index || TESTP(c2under, PRIME)) { + F->active_count--; + RESET(c2under, ACTIVE); + } else { + SET(c2under, ACTIVE); + } + } + + /* Initialize the raising and unassigned sets */ + (void) set_copy(RAISE, GETSET(F, c1index)); + (void) set_diff(FREESET, cube.fullset, RAISE); + + /* Determine parts which must be lowered */ + essen_parts(R, F, RAISE, FREESET); + + /* Determine parts which can always be raised */ + essen_raising(R, RAISE, FREESET); + + /* See which, if any, of the reduced cubes we can cover */ + foreachi_set(F, c2index, c2under) { + if (TESTP(c2under, ACTIVE)) { + /* See if this cube can be covered by an expansion */ + if (setp_implies(c2under, RAISE) || + feasibly_covered(R, c2under, RAISE, temp)) { + + /* See if c1under can expanded to cover c2 reduced against + * (F - c1) u c1under; if so, c2 can definitely be removed ! + */ + + /* Copy F and replace c1 with c1under */ + F1 = sf_save(Foriginal); + (void) set_copy(GETSET(F1, c1index), GETSET(F, c1index)); + + /* Reduce c2 against ((F - c1) u c1under) */ + FD = cube2list(F1, D); + c2essential = reduce_cube(FD, GETSET(F1, c2index)); + free_cubelist(FD); + sf_free(F1); + + /* See if c2essential is covered by an expansion of c1under */ + if (feasibly_covered(R, c2essential, RAISE, temp)) { + (void) set_or(temp, RAISE, c2essential); + RESET(temp, PRIME); /* cube not prime */ + *G = sf_addset(*G, temp); + } + set_free(c2essential); + } + } + } + + free_cube(RAISE); + free_cube(FREESET); + free_cube(temp); +} + +/* irred_gasp -- Add new primes to F and find an irredundant subset */ +pcover irred_gasp(F, D, G) +pcover F, D, G; /* G is disposed of */ +{ + if (G->count != 0) + F = irredundant(sf_append(F, G), D); + else + free_cover(G); + return F; +} + + +/* last_gasp */ +pcover last_gasp(F, D, R, cost) +pcover F, D, R; +cost_t *cost; +{ + pcover G, G1; + + EXECUTE(G = reduce_gasp(F, D), GREDUCE_TIME, G, *cost); + EXECUTE(G1 = expand_gasp(G, D, R, F), GEXPAND_TIME, G1, *cost); + free_cover(G); + EXECUTE(F = irred_gasp(F, D, G1), GIRRED_TIME, F, *cost); + return F; +} + + +/* super_gasp */ +pcover super_gasp(F, D, R, cost) +pcover F, D, R; +cost_t *cost; +{ + pcover G, G1; + + EXECUTE(G = reduce_gasp(F, D), GREDUCE_TIME, G, *cost); + EXECUTE(G1 = all_primes(G, R), GEXPAND_TIME, G1, *cost); + free_cover(G); + EXEC(G = sf_dupl(sf_append(F, G1)), "NEWPRIMES", G); + EXECUTE(F = irredundant(G, D), IRRED_TIME, F, *cost); + return F; +} diff --git a/src/misc/espresso/gimpel.c b/src/misc/espresso/gimpel.c new file mode 100644 index 00000000..648bb64a --- /dev/null +++ b/src/misc/espresso/gimpel.c @@ -0,0 +1,106 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +#include "mincov_int.h" + + +/* + * check for: + * + * c1 c2 rest + * -- -- --- + * 1 1 0 0 0 0 <-- primary row + * 1 0 S1 <-- secondary row + * 0 1 T1 + * 0 1 T2 + * 0 1 Tn + * 0 0 R + */ + +int +gimpel_reduce(A, select, weight, lb, bound, depth, stats, best) +sm_matrix *A; +solution_t *select; +int *weight; +int lb; +int bound; +int depth; +stats_t *stats; +solution_t **best; +{ + register sm_row *prow, *save_sec; + register sm_col *c1, *c2; + register sm_element *p, *p1; + int c1_col_num, c2_col_num, primary_row_num, secondary_row_num; + int reduce_it; + + reduce_it = 0; + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + if (prow->length == 2) { + c1 = sm_get_col(A, prow->first_col->col_num); + c2 = sm_get_col(A, prow->last_col->col_num); + if (c1->length == 2) { + reduce_it = 1; + } else if (c2->length == 2) { + c1 = sm_get_col(A, prow->last_col->col_num); + c2 = sm_get_col(A, prow->first_col->col_num); + reduce_it = 1; + } + if (reduce_it) { + primary_row_num = prow->row_num; + secondary_row_num = c1->first_row->row_num; + if (secondary_row_num == primary_row_num) { + secondary_row_num = c1->last_row->row_num; + } + break; + } + } + } + + if (reduce_it) { + c1_col_num = c1->col_num; + c2_col_num = c2->col_num; + save_sec = sm_row_dup(sm_get_row(A, secondary_row_num)); + sm_row_remove(save_sec, c1_col_num); + + for(p = c2->first_row; p != 0; p = p->next_row) { + if (p->row_num != primary_row_num) { + /* merge rows S1 and T */ + for(p1 = save_sec->first_col; p1 != 0; p1 = p1->next_col) { + (void) sm_insert(A, p->row_num, p1->col_num); + } + } + } + + sm_delcol(A, c1_col_num); + sm_delcol(A, c2_col_num); + sm_delrow(A, primary_row_num); + sm_delrow(A, secondary_row_num); + + stats->gimpel_count++; + stats->gimpel++; + *best = sm_mincov(A, select, weight, lb-1, bound-1, depth, stats); + stats->gimpel--; + + if (*best != NIL(solution_t)) { + /* is secondary row covered ? */ + if (sm_row_intersects(save_sec, (*best)->row)) { + /* yes, actually select c2 */ + solution_add(*best, weight, c2_col_num); + } else { + solution_add(*best, weight, c1_col_num); + } + } + + sm_row_free(save_sec); + return 1; + } else { + return 0; + } +} diff --git a/src/misc/espresso/globals.c b/src/misc/espresso/globals.c new file mode 100644 index 00000000..d04771e9 --- /dev/null +++ b/src/misc/espresso/globals.c @@ -0,0 +1,76 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +#include "espresso.h" + +/* + * Global Variable Declarations + */ + +unsigned int debug; /* debug parameter */ +bool verbose_debug; /* -v: whether to print a lot */ +char *total_name[TIME_COUNT]; /* basic function names */ +long total_time[TIME_COUNT]; /* time spent in basic fcts */ +int total_calls[TIME_COUNT]; /* # calls to each fct */ + +bool echo_comments; /* turned off by -eat option */ +bool echo_unknown_commands; /* always true ?? */ +bool force_irredundant; /* -nirr command line option */ +bool skip_make_sparse; +bool kiss; /* -kiss command line option */ +bool pos; /* -pos command line option */ +bool print_solution; /* -x command line option */ +bool recompute_onset; /* -onset command line option */ +bool remove_essential; /* -ness command line option */ +bool single_expand; /* -fast command line option */ +bool summary; /* -s command line option */ +bool trace; /* -t command line option */ +bool unwrap_onset; /* -nunwrap command line option */ +bool use_random_order; /* -random command line option */ +bool use_super_gasp; /* -strong command line option */ +char *filename; /* filename PLA was read from */ + +struct pla_types_struct pla_types[] = { + "-f", F_type, + "-r", R_type, + "-d", D_type, + "-fd", FD_type, + "-fr", FR_type, + "-dr", DR_type, + "-fdr", FDR_type, + "-fc", F_type | CONSTRAINTS_type, + "-rc", R_type | CONSTRAINTS_type, + "-dc", D_type | CONSTRAINTS_type, + "-fdc", FD_type | CONSTRAINTS_type, + "-frc", FR_type | CONSTRAINTS_type, + "-drc", DR_type | CONSTRAINTS_type, + "-fdrc", FDR_type | CONSTRAINTS_type, + "-pleasure", PLEASURE_type, + "-eqn", EQNTOTT_type, + "-eqntott", EQNTOTT_type, + "-kiss", KISS_type, + "-cons", CONSTRAINTS_type, + "-scons", SYMBOLIC_CONSTRAINTS_type, + 0, 0 +}; + + +struct cube_struct cube, temp_cube_save; +struct cdata_struct cdata, temp_cdata_save; + +int bit_count[256] = { + 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8 +}; diff --git a/src/misc/espresso/hack.c b/src/misc/espresso/hack.c new file mode 100644 index 00000000..927f5341 --- /dev/null +++ b/src/misc/espresso/hack.c @@ -0,0 +1,641 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +#include "espresso.h" + +map_dcset(PLA) +pPLA PLA; +{ + int var, i; + pcover Tplus, Tminus, Tplusbar, Tminusbar; + pcover newf, term1, term2, dcset, dcsetbar; + pcube cplus, cminus, last, p; + + if (PLA->label == NIL(char *) || PLA->label[0] == NIL(char)) + return; + + /* try to find a binary variable named "DONT_CARE" */ + var = -1; + for(i = 0; i < cube.num_binary_vars * 2; i++) { + if (strncmp(PLA->label[i], "DONT_CARE", 9) == 0 || + strncmp(PLA->label[i], "DONTCARE", 8) == 0 || + strncmp(PLA->label[i], "dont_care", 9) == 0 || + strncmp(PLA->label[i], "dontcare", 8) == 0) { + var = i/2; + break; + } + } + if (var == -1) { + return; + } + + /* form the cofactor cubes for the don't-care variable */ + cplus = set_save(cube.fullset); + cminus = set_save(cube.fullset); + set_remove(cplus, var*2); + set_remove(cminus, var*2 + 1); + + /* form the don't-care set */ + EXEC(simp_comp(cofactor(cube1list(PLA->F), cplus), &Tplus, &Tplusbar), + "simpcomp+", Tplus); + EXEC(simp_comp(cofactor(cube1list(PLA->F), cminus), &Tminus, &Tminusbar), + "simpcomp-", Tminus); + EXEC(term1 = cv_intersect(Tplus, Tminusbar), "term1 ", term1); + EXEC(term2 = cv_intersect(Tminus, Tplusbar), "term2 ", term2); + EXEC(dcset = sf_union(term1, term2), "union ", dcset); + EXEC(simp_comp(cube1list(dcset), &PLA->D, &dcsetbar), "simplify", PLA->D); + EXEC(newf = cv_intersect(PLA->F, dcsetbar), "separate ", PLA->F); + free_cover(PLA->F); + PLA->F = newf; + free_cover(Tplus); + free_cover(Tminus); + free_cover(Tplusbar); + free_cover(Tminusbar); + free_cover(dcsetbar); + + /* remove any cubes dependent on the DONT_CARE variable */ + (void) sf_active(PLA->F); + foreach_set(PLA->F, last, p) { + if (! is_in_set(p, var*2) || ! is_in_set(p, var*2+1)) { + RESET(p, ACTIVE); + } + } + PLA->F = sf_inactive(PLA->F); + + /* resize the cube and delete the don't-care variable */ + setdown_cube(); + for(i = 2*var+2; i < cube.size; i++) { + PLA->label[i-2] = PLA->label[i]; + } + for(i = var+1; i < cube.num_vars; i++) { + cube.part_size[i-1] = cube.part_size[i]; + } + cube.num_binary_vars--; + cube.num_vars--; + cube_setup(); + PLA->F = sf_delc(PLA->F, 2*var, 2*var+1); + PLA->D = sf_delc(PLA->D, 2*var, 2*var+1); +} + +map_output_symbolic(PLA) +pPLA PLA; +{ + pset_family newF, newD; + pset compress; + symbolic_t *p1; + symbolic_list_t *p2; + int i, bit, tot_size, base, old_size; + + /* Remove the DC-set from the ON-set (is this necessary ??) */ + if (PLA->D->count > 0) { + sf_free(PLA->F); + PLA->F = complement(cube2list(PLA->D, PLA->R)); + } + + /* tot_size = width added for all symbolic variables */ + tot_size = 0; + for(p1=PLA->symbolic_output; p1!=NIL(symbolic_t); p1=p1->next) { + for(p2=p1->symbolic_list; p2!=NIL(symbolic_list_t); p2=p2->next) { + if (p2->pos<0 || p2->pos>=cube.part_size[cube.output]) { + fatal("symbolic-output index out of range"); +/* } else if (p2->variable != cube.output) { + fatal("symbolic-output label must be an output");*/ + } + } + tot_size += 1 << p1->symbolic_list_length; + } + + /* adjust the indices to skip over new outputs */ + for(p1=PLA->symbolic_output; p1!=NIL(symbolic_t); p1=p1->next) { + for(p2=p1->symbolic_list; p2!=NIL(symbolic_list_t); p2=p2->next) { + p2->pos += tot_size; + } + } + + /* resize the cube structure -- add enough for the one-hot outputs */ + old_size = cube.size; + cube.part_size[cube.output] += tot_size; + setdown_cube(); + cube_setup(); + + /* insert space in the output part for the one-hot output */ + base = cube.first_part[cube.output]; + PLA->F = sf_addcol(PLA->F, base, tot_size); + PLA->D = sf_addcol(PLA->D, base, tot_size); + PLA->R = sf_addcol(PLA->R, base, tot_size); + + /* do the real work */ + for(p1=PLA->symbolic_output; p1!=NIL(symbolic_t); p1=p1->next) { + newF = new_cover(100); + newD = new_cover(100); + find_inputs(NIL(set_family_t), PLA, p1->symbolic_list, base, 0, + &newF, &newD); +/* + * Not sure what this means + find_dc_inputs(PLA, p1->symbolic_list, + base, 1 << p1->symbolic_list_length, &newF, &newD); + */ + free_cover(PLA->F); + PLA->F = newF; +/* + * retain OLD DC-set -- but we've lost the don't-care arc information + * (it defaults to branch to the zero state) + free_cover(PLA->D); + PLA->D = newD; + */ + free_cover(newD); + base += 1 << p1->symbolic_list_length; + } + + /* delete the old outputs, and resize the cube */ + compress = set_full(newF->sf_size); + for(p1=PLA->symbolic_output; p1!=NIL(symbolic_t); p1=p1->next) { + for(p2=p1->symbolic_list; p2!=NIL(symbolic_list_t); p2=p2->next) { + bit = cube.first_part[cube.output] + p2->pos; + set_remove(compress, bit); + } + } + cube.part_size[cube.output] -= newF->sf_size - set_ord(compress); + setdown_cube(); + cube_setup(); + PLA->F = sf_compress(PLA->F, compress); + PLA->D = sf_compress(PLA->D, compress); + if (cube.size != PLA->F->sf_size) fatal("error"); + + /* Quick minimization */ + PLA->F = sf_contain(PLA->F); + PLA->D = sf_contain(PLA->D); + for(i = 0; i < cube.num_vars; i++) { + PLA->F = d1merge(PLA->F, i); + PLA->D = d1merge(PLA->D, i); + } + PLA->F = sf_contain(PLA->F); + PLA->D = sf_contain(PLA->D); + + free_cover(PLA->R); + PLA->R = new_cover(0); + + symbolic_hack_labels(PLA, PLA->symbolic_output, + compress, cube.size, old_size, tot_size); + set_free(compress); +} + + +find_inputs(A, PLA, list, base, value, newF, newD) +pcover A; +pPLA PLA; +symbolic_list_t *list; +int base, value; +pcover *newF, *newD; +{ + pcover S, S1; + register pset last, p; + + /* + * A represents th 'input' values for which the outputs assume + * the integer value 'value + */ + if (list == NIL(symbolic_list_t)) { + /* + * Simulate these inputs against the on-set; then, insert into the + * new on-set a 1 in the proper position + */ + S = cv_intersect(A, PLA->F); + foreach_set(S, last, p) { + set_insert(p, base + value); + } + *newF = sf_append(*newF, S); + + /* + * 'simulate' these inputs against the don't-care set + S = cv_intersect(A, PLA->D); + *newD = sf_append(*newD, S); + */ + + } else { + /* intersect and recur with the OFF-set */ + S = cof_output(PLA->R, cube.first_part[cube.output] + list->pos); + if (A != NIL(set_family_t)) { + S1 = cv_intersect(A, S); + free_cover(S); + S = S1; + } + find_inputs(S, PLA, list->next, base, value*2, newF, newD); + free_cover(S); + + /* intersect and recur with the ON-set */ + S = cof_output(PLA->F, cube.first_part[cube.output] + list->pos); + if (A != NIL(set_family_t)) { + S1 = cv_intersect(A, S); + free_cover(S); + S = S1; + } + find_inputs(S, PLA, list->next, base, value*2 + 1, newF, newD); + free_cover(S); + } +} + + +#if 0 +find_dc_inputs(PLA, list, base, maxval, newF, newD) +pPLA PLA; +symbolic_list_t *list; +int base, maxval; +pcover *newF, *newD; +{ + pcover A, S, S1; + symbolic_list_t *p2; + register pset p, last; + register int i; + + /* painfully find the points for which the symbolic output is dc */ + A = NIL(set_family_t); + for(p2=list; p2!=NIL(symbolic_list_t); p2=p2->next) { + S = cof_output(PLA->D, cube.first_part[cube.output] + p2->pos); + if (A == NIL(set_family_t)) { + A = S; + } else { + S1 = cv_intersect(A, S); + free_cover(S); + free_cover(A); + A = S1; + } + } + + S = cv_intersect(A, PLA->F); + *newF = sf_append(*newF, S); + + S = cv_intersect(A, PLA->D); + foreach_set(S, last, p) { + for(i = base; i < base + maxval; i++) { + set_insert(p, i); + } + } + *newD = sf_append(*newD, S); + free_cover(A); +} +#endif + +map_symbolic(PLA) +pPLA PLA; +{ + symbolic_t *p1; + symbolic_list_t *p2; + int var, base, num_vars, num_binary_vars, *new_part_size; + int new_size, size_added, num_deleted_vars, num_added_vars, newvar; + pset compress; + + /* Verify legal values are in the symbolic lists */ + for(p1 = PLA->symbolic; p1 != NIL(symbolic_t); p1 = p1->next) { + for(p2=p1->symbolic_list; p2!=NIL(symbolic_list_t); p2=p2->next) { + if (p2->variable < 0 || p2->variable >= cube.num_binary_vars) { + fatal(".symbolic requires binary variables"); + } + } + } + + /* + * size_added = width added for all symbolic variables + * num_deleted_vars = # binary variables to be deleted + * num_added_vars = # new mv variables + * compress = a cube which will be used to compress the set families + */ + size_added = 0; + num_added_vars = 0; + for(p1 = PLA->symbolic; p1 != NIL(symbolic_t); p1 = p1->next) { + size_added += 1 << p1->symbolic_list_length; + num_added_vars++; + } + compress = set_full(PLA->F->sf_size + size_added); + for(p1 = PLA->symbolic; p1 != NIL(symbolic_t); p1 = p1->next) { + for(p2=p1->symbolic_list; p2!=NIL(symbolic_list_t); p2=p2->next) { + set_remove(compress, p2->variable*2); + set_remove(compress, p2->variable*2+1); + } + } + num_deleted_vars = ((PLA->F->sf_size + size_added) - set_ord(compress))/2; + + /* compute the new cube constants */ + num_vars = cube.num_vars - num_deleted_vars + num_added_vars; + num_binary_vars = cube.num_binary_vars - num_deleted_vars; + new_size = cube.size - num_deleted_vars*2 + size_added; + new_part_size = ALLOC(int, num_vars); + new_part_size[num_vars-1] = cube.part_size[cube.num_vars-1]; + for(var = cube.num_binary_vars; var < cube.num_vars-1; var++) { + new_part_size[var-num_deleted_vars] = cube.part_size[var]; + } + + /* re-size the covers, opening room for the new mv variables */ + base = cube.first_part[cube.output]; + PLA->F = sf_addcol(PLA->F, base, size_added); + PLA->D = sf_addcol(PLA->D, base, size_added); + PLA->R = sf_addcol(PLA->R, base, size_added); + + /* compute the values for the new mv variables */ + newvar = (cube.num_vars - 1) - num_deleted_vars; + for(p1 = PLA->symbolic; p1 != NIL(symbolic_t); p1 = p1->next) { + PLA->F = map_symbolic_cover(PLA->F, p1->symbolic_list, base); + PLA->D = map_symbolic_cover(PLA->D, p1->symbolic_list, base); + PLA->R = map_symbolic_cover(PLA->R, p1->symbolic_list, base); + base += 1 << p1->symbolic_list_length; + new_part_size[newvar++] = 1 << p1->symbolic_list_length; + } + + /* delete the binary variables which disappear */ + PLA->F = sf_compress(PLA->F, compress); + PLA->D = sf_compress(PLA->D, compress); + PLA->R = sf_compress(PLA->R, compress); + + symbolic_hack_labels(PLA, PLA->symbolic, compress, + new_size, cube.size, size_added); + setdown_cube(); + FREE(cube.part_size); + cube.num_vars = num_vars; + cube.num_binary_vars = num_binary_vars; + cube.part_size = new_part_size; + cube_setup(); + set_free(compress); +} + + +pcover map_symbolic_cover(T, list, base) +pcover T; +symbolic_list_t *list; +int base; +{ + pset last, p; + foreach_set(T, last, p) { + form_bitvector(p, base, 0, list); + } + return T; +} + + +form_bitvector(p, base, value, list) +pset p; /* old cube, looking at binary variables */ +int base; /* where in mv cube the new variable starts */ +int value; /* current value for this recursion */ +symbolic_list_t *list; /* current place in the symbolic list */ +{ + if (list == NIL(symbolic_list_t)) { + set_insert(p, base + value); + } else { + switch(GETINPUT(p, list->variable)) { + case ZERO: + form_bitvector(p, base, value*2, list->next); + break; + case ONE: + form_bitvector(p, base, value*2+1, list->next); + break; + case TWO: + form_bitvector(p, base, value*2, list->next); + form_bitvector(p, base, value*2+1, list->next); + break; + default: + fatal("bad cube in form_bitvector"); + } + } +} + + +symbolic_hack_labels(PLA, list, compress, new_size, old_size, size_added) +pPLA PLA; +symbolic_t *list; +pset compress; +int new_size, old_size, size_added; +{ + int i, base; + char **oldlabel; + symbolic_t *p1; + symbolic_label_t *p3; + + /* hack with the labels */ + if ((oldlabel = PLA->label) == NIL(char *)) + return; + PLA->label = ALLOC(char *, new_size); + for(i = 0; i < new_size; i++) { + PLA->label[i] = NIL(char); + } + + /* copy the binary variable labels and unchanged mv variable labels */ + base = 0; + for(i = 0; i < cube.first_part[cube.output]; i++) { + if (is_in_set(compress, i)) { + PLA->label[base++] = oldlabel[i]; + } else { + if (oldlabel[i] != NIL(char)) { + FREE(oldlabel[i]); + } + } + } + + /* add the user-defined labels for the symbolic outputs */ + for(p1 = list; p1 != NIL(symbolic_t); p1 = p1->next) { + p3 = p1->symbolic_label; + for(i = 0; i < (1 << p1->symbolic_list_length); i++) { + if (p3 == NIL(symbolic_label_t)) { + PLA->label[base+i] = ALLOC(char, 10); + (void) sprintf(PLA->label[base+i], "X%d", i); + } else { + PLA->label[base+i] = p3->label; + p3 = p3->next; + } + } + base += 1 << p1->symbolic_list_length; + } + + /* copy the labels for the binary outputs which remain */ + for(i = cube.first_part[cube.output]; i < old_size; i++) { + if (is_in_set(compress, i + size_added)) { + PLA->label[base++] = oldlabel[i]; + } else { + if (oldlabel[i] != NIL(char)) { + FREE(oldlabel[i]); + } + } + } + FREE(oldlabel); +} + +static pcover fsm_simplify(F) +pcover F; +{ + pcover D, R; + D = new_cover(0); + R = complement(cube1list(F)); + F = espresso(F, D, R); + free_cover(D); + free_cover(R); + return F; +} + + +disassemble_fsm(PLA, verbose_mode) +pPLA PLA; +int verbose_mode; +{ + int nin, nstates, nout; + int before, after, present_state, next_state, i, j; + pcube next_state_mask, present_state_mask, state_mask, p, p1, last; + pcover go_nowhere, F, tF; + + /* We make the DISGUSTING assumption that the first 'n' outputs have + * been created by .symbolic-output, and represent a one-hot encoding + * of the next state. 'n' is the size of the second-to-last multiple- + * valued variable (i.e., before the outputs + */ + + if (cube.num_vars - cube.num_binary_vars != 2) { + (void) fprintf(stderr, + "use .symbolic and .symbolic-output to specify\n"); + (void) fprintf(stderr, + "the present state and next state field information\n"); + fatal("disassemble_pla: need two multiple-valued variables\n"); + } + + nin = cube.num_binary_vars; + nstates = cube.part_size[cube.num_binary_vars]; + nout = cube.part_size[cube.num_vars - 1]; + if (nout < nstates) { + (void) fprintf(stderr, + "use .symbolic and .symbolic-output to specify\n"); + (void) fprintf(stderr, + "the present state and next state field information\n"); + fatal("disassemble_pla: # outputs < # states\n"); + } + + + present_state = cube.first_part[cube.num_binary_vars]; + present_state_mask = new_cube(); + for(i = 0; i < nstates; i++) { + set_insert(present_state_mask, i + present_state); + } + + next_state = cube.first_part[cube.num_binary_vars+1]; + next_state_mask = new_cube(); + for(i = 0; i < nstates; i++) { + set_insert(next_state_mask, i + next_state); + } + + state_mask = set_or(new_cube(), next_state_mask, present_state_mask); + + F = new_cover(10); + + + /* + * check for arcs which go from ANY state to state #i + */ + for(i = 0; i < nstates; i++) { + tF = new_cover(10); + foreach_set(PLA->F, last, p) { + if (setp_implies(present_state_mask, p)) { /* from any state ! */ + if (is_in_set(p, next_state + i)) { + tF = sf_addset(tF, p); + } + } + } + before = tF->count; + if (before > 0) { + tF = fsm_simplify(tF); + /* don't allow the next state to disappear ... */ + foreach_set(tF, last, p) { + set_insert(p, next_state + i); + } + after = tF->count; + F = sf_append(F, tF); + if (verbose_mode) { + printf("# state EVERY to %d, before=%d after=%d\n", + i, before, after); + } + } + } + + + /* + * some 'arcs' may NOT have a next state -- handle these + * we must unravel the present state part + */ + go_nowhere = new_cover(10); + foreach_set(PLA->F, last, p) { + if (setp_disjoint(p, next_state_mask)) { /* no next state !! */ + go_nowhere = sf_addset(go_nowhere, p); + } + } + before = go_nowhere->count; + go_nowhere = unravel_range(go_nowhere, + cube.num_binary_vars, cube.num_binary_vars); + after = go_nowhere->count; + F = sf_append(F, go_nowhere); + if (verbose_mode) { + printf("# state ANY to NOWHERE, before=%d after=%d\n", before, after); + } + + + /* + * minimize cover for all arcs from state #i to state #j + */ + for(i = 0; i < nstates; i++) { + for(j = 0; j < nstates; j++) { + tF = new_cover(10); + foreach_set(PLA->F, last, p) { + /* not EVERY state */ + if (! setp_implies(present_state_mask, p)) { + if (is_in_set(p, present_state + i)) { + if (is_in_set(p, next_state + j)) { + p1 = set_save(p); + set_diff(p1, p1, state_mask); + set_insert(p1, present_state + i); + set_insert(p1, next_state + j); + tF = sf_addset(tF, p1); + set_free(p1); + } + } + } + } + before = tF->count; + if (before > 0) { + tF = fsm_simplify(tF); + /* don't allow the next state to disappear ... */ + foreach_set(tF, last, p) { + set_insert(p, next_state + j); + } + after = tF->count; + F = sf_append(F, tF); + if (verbose_mode) { + printf("# state %d to %d, before=%d after=%d\n", + i, j, before, after); + } + } + } + } + + + free_cube(state_mask); + free_cube(present_state_mask); + free_cube(next_state_mask); + + free_cover(PLA->F); + PLA->F = F; + free_cover(PLA->D); + PLA->D = new_cover(0); + + setdown_cube(); + FREE(cube.part_size); + cube.num_binary_vars = nin; + cube.num_vars = nin + 3; + cube.part_size = ALLOC(int, cube.num_vars); + cube.part_size[cube.num_binary_vars] = nstates; + cube.part_size[cube.num_binary_vars+1] = nstates; + cube.part_size[cube.num_binary_vars+2] = nout - nstates; + cube_setup(); + + foreach_set(PLA->F, last, p) { + kiss_print_cube(stdout, PLA, p, "~1"); + } +} diff --git a/src/misc/espresso/indep.c b/src/misc/espresso/indep.c new file mode 100644 index 00000000..10b363a0 --- /dev/null +++ b/src/misc/espresso/indep.c @@ -0,0 +1,134 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +#include "mincov_int.h" + +static sm_matrix *build_intersection_matrix(); + + +#if 0 +/* + * verify that all rows in 'indep' are actually independent ! + */ +static int +verify_indep_set(A, indep) +sm_matrix *A; +sm_row *indep; +{ + register sm_row *prow, *prow1; + register sm_element *p, *p1; + + for(p = indep->first_col; p != 0; p = p->next_col) { + prow = sm_get_row(A, p->col_num); + for(p1 = p->next_col; p1 != 0; p1 = p1->next_col) { + prow1 = sm_get_row(A, p1->col_num); + if (sm_row_intersects(prow, prow1)) { + return 0; + } + } + } + return 1; +} +#endif + +solution_t * +sm_maximal_independent_set(A, weight) +sm_matrix *A; +int *weight; +{ + register sm_row *best_row, *prow; + register sm_element *p; + int least_weight; + sm_row *save; + sm_matrix *B; + solution_t *indep; + + indep = solution_alloc(); + B = build_intersection_matrix(A); + + while (B->nrows > 0) { + /* Find the row which is disjoint from a maximum number of rows */ + best_row = B->first_row; + for(prow = B->first_row->next_row; prow != 0; prow = prow->next_row) { + if (prow->length < best_row->length) { + best_row = prow; + } + } + + /* Find which element in this row has least weight */ + if (weight == NIL(int)) { + least_weight = 1; + } else { + prow = sm_get_row(A, best_row->row_num); + least_weight = weight[prow->first_col->col_num]; + for(p = prow->first_col->next_col; p != 0; p = p->next_col) { + if (weight[p->col_num] < least_weight) { + least_weight = weight[p->col_num]; + } + } + } + indep->cost += least_weight; + (void) sm_row_insert(indep->row, best_row->row_num); + + /* Discard the rows which intersect this row */ + save = sm_row_dup(best_row); + for(p = save->first_col; p != 0; p = p->next_col) { + sm_delrow(B, p->col_num); + sm_delcol(B, p->col_num); + } + sm_row_free(save); + } + + sm_free(B); + +/* + if (! verify_indep_set(A, indep->row)) { + fail("sm_maximal_independent_set: row set is not independent"); + } +*/ + return indep; +} + +static sm_matrix * +build_intersection_matrix(A) +sm_matrix *A; +{ + register sm_row *prow, *prow1; + register sm_element *p, *p1; + register sm_col *pcol; + sm_matrix *B; + + /* Build row-intersection matrix */ + B = sm_alloc(); + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + + /* Clear flags on all rows we can reach from row 'prow' */ + for(p = prow->first_col; p != 0; p = p->next_col) { + pcol = sm_get_col(A, p->col_num); + for(p1 = pcol->first_row; p1 != 0; p1 = p1->next_row) { + prow1 = sm_get_row(A, p1->row_num); + prow1->flag = 0; + } + } + + /* Now record which rows can be reached */ + for(p = prow->first_col; p != 0; p = p->next_col) { + pcol = sm_get_col(A, p->col_num); + for(p1 = pcol->first_row; p1 != 0; p1 = p1->next_row) { + prow1 = sm_get_row(A, p1->row_num); + if (! prow1->flag) { + prow1->flag = 1; + (void) sm_insert(B, prow->row_num, prow1->row_num); + } + } + } + } + + return B; +} diff --git a/src/misc/espresso/irred.c b/src/misc/espresso/irred.c new file mode 100644 index 00000000..384e698f --- /dev/null +++ b/src/misc/espresso/irred.c @@ -0,0 +1,440 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +#include "espresso.h" + +static void fcube_is_covered(); +static void ftautology(); +static bool ftaut_special_cases(); + + +static int Rp_current; + +/* + * irredundant -- Return a minimal subset of F + */ + +pcover +irredundant(F, D) +pcover F, D; +{ + mark_irredundant(F, D); + return sf_inactive(F); +} + + +/* + * mark_irredundant -- find redundant cubes, and mark them "INACTIVE" + */ + +void +mark_irredundant(F, D) +pcover F, D; +{ + pcover E, Rt, Rp; + pset p, p1, last; + sm_matrix *table; + sm_row *cover; + sm_element *pe; + + /* extract a minimum cover */ + irred_split_cover(F, D, &E, &Rt, &Rp); + table = irred_derive_table(D, E, Rp); + cover = sm_minimum_cover(table, NIL(int), /* heuristic */ 1, /* debug */ 0); + + /* mark the cubes for the result */ + foreach_set(F, last, p) { + RESET(p, ACTIVE); + RESET(p, RELESSEN); + } + foreach_set(E, last, p) { + p1 = GETSET(F, SIZE(p)); + assert(setp_equal(p1, p)); + SET(p1, ACTIVE); + SET(p1, RELESSEN); /* for essen(), mark as rel. ess. */ + } + sm_foreach_row_element(cover, pe) { + p1 = GETSET(F, pe->col_num); + SET(p1, ACTIVE); + } + + if (debug & IRRED) { + printf("# IRRED: F=%d E=%d R=%d Rt=%d Rp=%d Rc=%d Final=%d Bound=%d\n", + F->count, E->count, Rt->count+Rp->count, Rt->count, Rp->count, + cover->length, E->count + cover->length, 0); + } + + free_cover(E); + free_cover(Rt); + free_cover(Rp); + sm_free(table); + sm_row_free(cover); +} + +/* + * irred_split_cover -- find E, Rt, and Rp from the cover F, D + * + * E -- relatively essential cubes + * Rt -- totally redundant cubes + * Rp -- partially redundant cubes + */ + +void +irred_split_cover(F, D, E, Rt, Rp) +pcover F, D; +pcover *E, *Rt, *Rp; +{ + register pcube p, last; + register int index; + pcover R; + pcube *FD, *ED; + + /* number the cubes of F -- these numbers track into E, Rp, Rt, etc. */ + index = 0; + foreach_set(F, last, p) { + PUTSIZE(p, index); + index++; + } + + *E = new_cover(10); + *Rt = new_cover(10); + *Rp = new_cover(10); + R = new_cover(10); + + /* Split F into E and R */ + FD = cube2list(F, D); + foreach_set(F, last, p) { + if (cube_is_covered(FD, p)) { + R = sf_addset(R, p); + } else { + *E = sf_addset(*E, p); + } + if (debug & IRRED1) { + (void) printf("IRRED1: zr=%d ze=%d to-go=%d time=%s\n", + R->count, (*E)->count, F->count - (R->count + (*E)->count), + print_time(ptime())); + } + } + free_cubelist(FD); + + /* Split R into Rt and Rp */ + ED = cube2list(*E, D); + foreach_set(R, last, p) { + if (cube_is_covered(ED, p)) { + *Rt = sf_addset(*Rt, p); + } else { + *Rp = sf_addset(*Rp, p); + } + if (debug & IRRED1) { + (void) printf("IRRED1: zr=%d zrt=%d to-go=%d time=%s\n", + (*Rp)->count, (*Rt)->count, + R->count - ((*Rp)->count +(*Rt)->count), print_time(ptime())); + } + } + free_cubelist(ED); + + free_cover(R); +} + +/* + * irred_derive_table -- given the covers D, E and the set of + * partially redundant primes Rp, build a covering table showing + * possible selections of primes to cover Rp. + */ + +sm_matrix * +irred_derive_table(D, E, Rp) +pcover D, E, Rp; +{ + register pcube last, p, *list; + sm_matrix *table; + int size_last_dominance, i; + + /* Mark each cube in DE as not part of the redundant set */ + foreach_set(D, last, p) { + RESET(p, REDUND); + } + foreach_set(E, last, p) { + RESET(p, REDUND); + } + + /* Mark each cube in Rp as partially redundant */ + foreach_set(Rp, last, p) { + SET(p, REDUND); /* belongs to redundant set */ + } + + /* For each cube in Rp, find ways to cover its minterms */ + list = cube3list(D, E, Rp); + table = sm_alloc(); + size_last_dominance = 0; + i = 0; + foreach_set(Rp, last, p) { + Rp_current = SIZE(p); + fcube_is_covered(list, p, table); + RESET(p, REDUND); /* can now consider this cube redundant */ + if (debug & IRRED1) { + (void) printf("IRRED1: %d of %d to-go=%d, table=%dx%d time=%s\n", + i, Rp->count, Rp->count - i, + table->nrows, table->ncols, print_time(ptime())); + } + /* try to keep memory limits down by reducing table as we go along */ + if (table->nrows - size_last_dominance > 1000) { + (void) sm_row_dominance(table); + size_last_dominance = table->nrows; + if (debug & IRRED1) { + (void) printf("IRRED1: delete redundant rows, now %dx%d\n", + table->nrows, table->ncols); + } + } + i++; + } + free_cubelist(list); + + return table; +} + +/* cube_is_covered -- determine if a cubelist "covers" a single cube */ +bool +cube_is_covered(T, c) +pcube *T, c; +{ + return tautology(cofactor(T,c)); +} + + + +/* tautology -- answer the tautology question for T */ +bool +tautology(T) +pcube *T; /* T will be disposed of */ +{ + register pcube cl, cr; + register int best, result; + static int taut_level = 0; + + if (debug & TAUT) { + debug_print(T, "TAUTOLOGY", taut_level++); + } + + if ((result = taut_special_cases(T)) == MAYBE) { + cl = new_cube(); + cr = new_cube(); + best = binate_split_select(T, cl, cr, TAUT); + result = tautology(scofactor(T, cl, best)) && + tautology(scofactor(T, cr, best)); + free_cubelist(T); + free_cube(cl); + free_cube(cr); + } + + if (debug & TAUT) { + printf("exit TAUTOLOGY[%d]: %s\n", --taut_level, print_bool(result)); + } + return result; +} + +/* + * taut_special_cases -- check special cases for tautology + */ + +bool +taut_special_cases(T) +pcube *T; /* will be disposed if answer is determined */ +{ + register pcube *T1, *Tsave, p, ceil=cube.temp[0], temp=cube.temp[1]; + pcube *A, *B; + int var; + + /* Check for a row of all 1's which implies tautology */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (full_row(p, T[0])) { + free_cubelist(T); + return TRUE; + } + } + + /* Check for a column of all 0's which implies no tautology */ +start: + INLINEset_copy(ceil, T[0]); + for(T1 = T+2; (p = *T1++) != NULL; ) { + INLINEset_or(ceil, ceil, p); + } + if (! setp_equal(ceil, cube.fullset)) { + free_cubelist(T); + return FALSE; + } + + /* Collect column counts, determine unate variables, etc. */ + massive_count(T); + + /* If function is unate (and no row of all 1's), then no tautology */ + if (cdata.vars_unate == cdata.vars_active) { + free_cubelist(T); + return FALSE; + + /* If active in a single variable (and no column of 0's) then tautology */ + } else if (cdata.vars_active == 1) { + free_cubelist(T); + return TRUE; + + /* Check for unate variables, and reduce cover if there are any */ + } else if (cdata.vars_unate != 0) { + /* Form a cube "ceil" with full variables in the unate variables */ + (void) set_copy(ceil, cube.emptyset); + for(var = 0; var < cube.num_vars; var++) { + if (cdata.is_unate[var]) { + INLINEset_or(ceil, ceil, cube.var_mask[var]); + } + } + + /* Save only those cubes that are "full" in all unate variables */ + for(Tsave = T1 = T+2; (p = *T1++) != 0; ) { + if (setp_implies(ceil, set_or(temp, p, T[0]))) { + *Tsave++ = p; + } + } + *Tsave++ = NULL; + T[1] = (pcube) Tsave; + + if (debug & TAUT) { + printf("UNATE_REDUCTION: %d unate variables, reduced to %d\n", + cdata.vars_unate, CUBELISTSIZE(T)); + } + goto start; + + /* Check for component reduction */ + } else if (cdata.var_zeros[cdata.best] < CUBELISTSIZE(T) / 2) { + if (cubelist_partition(T, &A, &B, debug & TAUT) == 0) { + return MAYBE; + } else { + free_cubelist(T); + if (tautology(A)) { + free_cubelist(B); + return TRUE; + } else { + return tautology(B); + } + } + } + + /* We tried as hard as we could, but must recurse from here on */ + return MAYBE; +} + +/* fcube_is_covered -- determine exactly how a cubelist "covers" a cube */ +static void +fcube_is_covered(T, c, table) +pcube *T, c; +sm_matrix *table; +{ + ftautology(cofactor(T,c), table); +} + + +/* ftautology -- find ways to make a tautology */ +static void +ftautology(T, table) +pcube *T; /* T will be disposed of */ +sm_matrix *table; +{ + register pcube cl, cr; + register int best; + static int ftaut_level = 0; + + if (debug & TAUT) { + debug_print(T, "FIND_TAUTOLOGY", ftaut_level++); + } + + if (ftaut_special_cases(T, table) == MAYBE) { + cl = new_cube(); + cr = new_cube(); + best = binate_split_select(T, cl, cr, TAUT); + + ftautology(scofactor(T, cl, best), table); + ftautology(scofactor(T, cr, best), table); + + free_cubelist(T); + free_cube(cl); + free_cube(cr); + } + + if (debug & TAUT) { + (void) printf("exit FIND_TAUTOLOGY[%d]: table is %d by %d\n", + --ftaut_level, table->nrows, table->ncols); + } +} + +static bool +ftaut_special_cases(T, table) +pcube *T; /* will be disposed if answer is determined */ +sm_matrix *table; +{ + register pcube *T1, *Tsave, p, temp = cube.temp[0], ceil = cube.temp[1]; + int var, rownum; + + /* Check for a row of all 1's in the essential cubes */ + for(T1 = T+2; (p = *T1++) != 0; ) { + if (! TESTP(p, REDUND)) { + if (full_row(p, T[0])) { + /* subspace is covered by essentials -- no new rows for table */ + free_cubelist(T); + return TRUE; + } + } + } + + /* Collect column counts, determine unate variables, etc. */ +start: + massive_count(T); + + /* If function is unate, find the rows of all 1's */ + if (cdata.vars_unate == cdata.vars_active) { + /* find which nonessentials cover this subspace */ + rownum = table->last_row ? table->last_row->row_num+1 : 0; + (void) sm_insert(table, rownum, Rp_current); + for(T1 = T+2; (p = *T1++) != 0; ) { + if (TESTP(p, REDUND)) { + /* See if a redundant cube covers this leaf */ + if (full_row(p, T[0])) { + (void) sm_insert(table, rownum, (int) SIZE(p)); + } + } + } + free_cubelist(T); + return TRUE; + + /* Perform unate reduction if there are any unate variables */ + } else if (cdata.vars_unate != 0) { + /* Form a cube "ceil" with full variables in the unate variables */ + (void) set_copy(ceil, cube.emptyset); + for(var = 0; var < cube.num_vars; var++) { + if (cdata.is_unate[var]) { + INLINEset_or(ceil, ceil, cube.var_mask[var]); + } + } + + /* Save only those cubes that are "full" in all unate variables */ + for(Tsave = T1 = T+2; (p = *T1++) != 0; ) { + if (setp_implies(ceil, set_or(temp, p, T[0]))) { + *Tsave++ = p; + } + } + *Tsave++ = 0; + T[1] = (pcube) Tsave; + + if (debug & TAUT) { + printf("UNATE_REDUCTION: %d unate variables, reduced to %d\n", + cdata.vars_unate, CUBELISTSIZE(T)); + } + goto start; + } + + /* Not much we can do about it */ + return MAYBE; +} diff --git a/src/misc/espresso/main.c b/src/misc/espresso/main.c new file mode 100644 index 00000000..0a511c0e --- /dev/null +++ b/src/misc/espresso/main.c @@ -0,0 +1,746 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +/* + * Main driver for espresso + * + * Old style -do xxx, -out xxx, etc. are still supported. + */ + +#include "espresso.h" +#include "main.h" /* table definitions for options */ + +static FILE *last_fp; +static int input_type = FD_type; + + +main(argc, argv) +int argc; +char *argv[]; +{ + int i, j, first, last, strategy, out_type, option; + pPLA PLA, PLA1; + pcover F, Fold, Dold; + pset last1, p; + cost_t cost; + bool error, exact_cover; + long start; + extern char *util_optarg; + extern int util_optind; + + start = ptime(); + + error = FALSE; + init_runtime(); +#ifdef RANDOM + srandom(314973); +#endif + + option = 0; /* default -D: ESPRESSO */ + out_type = F_type; /* default -o: default is ON-set only */ + debug = 0; /* default -d: no debugging info */ + verbose_debug = FALSE; /* default -v: not verbose */ + print_solution = TRUE; /* default -x: print the solution (!) */ + summary = FALSE; /* default -s: no summary */ + trace = FALSE; /* default -t: no trace information */ + strategy = 0; /* default -S: strategy number */ + first = -1; /* default -R: select range */ + last = -1; + remove_essential = TRUE; /* default -e: */ + force_irredundant = TRUE; + unwrap_onset = TRUE; + single_expand = FALSE; + pos = FALSE; + recompute_onset = FALSE; + use_super_gasp = FALSE; + use_random_order = FALSE; + kiss = FALSE; + echo_comments = TRUE; + echo_unknown_commands = TRUE; + exact_cover = FALSE; /* for -qm option, the default */ + + backward_compatibility_hack(&argc, argv, &option, &out_type); + + + /* parse command line options*/ + while ((i = util_getopt(argc, argv, "D:S:de:o:r:stv:x")) != EOF) { + switch(i) { + case 'D': /* -Dcommand invokes a subcommand */ + for(j = 0; option_table[j].name != 0; j++) { + if (strcmp(util_optarg, option_table[j].name) == 0) { + option = j; + break; + } + } + if (option_table[j].name == 0) { + (void) fprintf(stderr, "%s: bad subcommand \"%s\"\n", + argv[0], util_optarg); + exit(1); + } + break; + + case 'o': /* -ooutput selects and output option */ + for(j = 0; pla_types[j].key != 0; j++) { + if (strcmp(util_optarg, pla_types[j].key+1) == 0) { + out_type = pla_types[j].value; + break; + } + } + if (pla_types[j].key == 0) { + (void) fprintf(stderr, "%s: bad output type \"%s\"\n", + argv[0], util_optarg); + exit(1); + } + break; + + case 'e': /* -eespresso selects an option for espresso */ + for(j = 0; esp_opt_table[j].name != 0; j++) { + if (strcmp(util_optarg, esp_opt_table[j].name) == 0) { + *(esp_opt_table[j].variable) = esp_opt_table[j].value; + break; + } + } + if (esp_opt_table[j].name == 0) { + (void) fprintf(stderr, "%s: bad espresso option \"%s\"\n", + argv[0], util_optarg); + exit(1); + } + break; + + case 'd': /* -d turns on (softly) all debug switches */ + debug = debug_table[0].value; + trace = TRUE; + summary = TRUE; + break; + + case 'v': /* -vdebug invokes a debug option */ + verbose_debug = TRUE; + for(j = 0; debug_table[j].name != 0; j++) { + if (strcmp(util_optarg, debug_table[j].name) == 0) { + debug |= debug_table[j].value; + break; + } + } + if (debug_table[j].name == 0) { + (void) fprintf(stderr, "%s: bad debug type \"%s\"\n", + argv[0], util_optarg); + exit(1); + } + break; + + case 't': + trace = TRUE; + break; + + case 's': + summary = TRUE; + break; + + case 'x': /* -x suppress printing of results */ + print_solution = FALSE; + break; + + case 'S': /* -S sets a strategy for several cmds */ + strategy = atoi(util_optarg); + break; + + case 'r': /* -r selects range (outputs or vars) */ + if (sscanf(util_optarg, "%d-%d", &first, &last) < 2) { + (void) fprintf(stderr, "%s: bad output range \"%s\"\n", + argv[0], util_optarg); + exit(1); + } + break; + + default: + usage(); + exit(1); + } + } + + /* provide version information and summaries */ + if (summary || trace) { + /* echo command line and arguments */ + printf("#"); + for(i = 0; i < argc; i++) { + printf(" %s", argv[i]); + } + printf("\n"); + printf("# %s\n", VERSION); + } + + /* the remaining arguments are argv[util_optind ... argc-1] */ + PLA = PLA1 = NIL(PLA_t); + switch(option_table[option].num_plas) { + case 2: + if (util_optind+2 < argc) fatal("trailing arguments on command line"); + getPLA(util_optind++, argc, argv, option, &PLA, out_type); + getPLA(util_optind++, argc, argv, option, &PLA1, out_type); + break; + case 1: + if (util_optind+1 < argc) fatal("trailing arguments on command line"); + getPLA(util_optind++, argc, argv, option, &PLA, out_type); + break; + } + if (util_optind < argc) fatal("trailing arguments on command line"); + + if (summary || trace) { + if (PLA != NIL(PLA_t)) PLA_summary(PLA); + if (PLA1 != NIL(PLA_t)) PLA_summary(PLA1); + } + +/* + * Now a case-statement to decide what to do + */ + + switch(option_table[option].key) { + + +/******************** Espresso operations ********************/ + + case KEY_ESPRESSO: + Fold = sf_save(PLA->F); + PLA->F = espresso(PLA->F, PLA->D, PLA->R); + EXECUTE(error=verify(PLA->F,Fold,PLA->D), VERIFY_TIME, PLA->F, cost); + if (error) { + print_solution = FALSE; + PLA->F = Fold; + (void) check_consistency(PLA); + } else { + free_cover(Fold); + } + break; + + case KEY_MANY_ESPRESSO: { + int pla_type; + do { + EXEC(PLA->F=espresso(PLA->F,PLA->D,PLA->R),"ESPRESSO ",PLA->F); + if (print_solution) { + fprint_pla(stdout, PLA, out_type); + (void) fflush(stdout); + } + pla_type = PLA->pla_type; + free_PLA(PLA); + setdown_cube(); + FREE(cube.part_size); + } while (read_pla(last_fp, TRUE, TRUE, pla_type, &PLA) != EOF); + exit(0); + } + + case KEY_simplify: + EXEC(PLA->F = simplify(cube1list(PLA->F)), "SIMPLIFY ", PLA->F); + break; + + case KEY_so: /* minimize all functions as single-output */ + if (strategy < 0 || strategy > 1) { + strategy = 0; + } + so_espresso(PLA, strategy); + break; + + case KEY_so_both: /* minimize all functions as single-output */ + if (strategy < 0 || strategy > 1) { + strategy = 0; + } + so_both_espresso(PLA, strategy); + break; + + case KEY_expand: /* execute expand */ + EXECUTE(PLA->F=expand(PLA->F,PLA->R,FALSE),EXPAND_TIME, PLA->F, cost); + break; + + case KEY_irred: /* extract minimal irredundant subset */ + EXECUTE(PLA->F = irredundant(PLA->F, PLA->D), IRRED_TIME, PLA->F, cost); + break; + + case KEY_reduce: /* perform reduction */ + EXECUTE(PLA->F = reduce(PLA->F, PLA->D), REDUCE_TIME, PLA->F, cost); + break; + + case KEY_essen: /* check for essential primes */ + foreach_set(PLA->F, last1, p) { + SET(p, RELESSEN); + RESET(p, NONESSEN); + } + EXECUTE(F = essential(&(PLA->F), &(PLA->D)), ESSEN_TIME, PLA->F, cost); + free_cover(F); + break; + + case KEY_super_gasp: + PLA->F = super_gasp(PLA->F, PLA->D, PLA->R, &cost); + break; + + case KEY_gasp: + PLA->F = last_gasp(PLA->F, PLA->D, PLA->R, &cost); + break; + + case KEY_make_sparse: /* make_sparse step of Espresso */ + PLA->F = make_sparse(PLA->F, PLA->D, PLA->R); + break; + + case KEY_exact: + exact_cover = TRUE; + + case KEY_qm: + Fold = sf_save(PLA->F); + PLA->F = minimize_exact(PLA->F, PLA->D, PLA->R, exact_cover); + EXECUTE(error=verify(PLA->F,Fold,PLA->D), VERIFY_TIME, PLA->F, cost); + if (error) { + print_solution = FALSE; + PLA->F = Fold; + (void) check_consistency(PLA); + } + free_cover(Fold); + break; + + case KEY_primes: /* generate all prime implicants */ + EXEC(PLA->F = primes_consensus(cube2list(PLA->F, PLA->D)), + "PRIMES ", PLA->F); + break; + + case KEY_map: /* print out a Karnaugh map of function */ + map(PLA->F); + print_solution = FALSE; + break; + + + +/******************** Output phase and bit pairing ********************/ + + case KEY_opo: /* sasao output phase assignment */ + phase_assignment(PLA, strategy); + break; + + case KEY_opoall: /* try all phase assignments (!) */ + if (first < 0 || first >= cube.part_size[cube.output]) { + first = 0; + } + if (last < 0 || last >= cube.part_size[cube.output]) { + last = cube.part_size[cube.output] - 1; + } + opoall(PLA, first, last, strategy); + break; + + case KEY_pair: /* find an optimal pairing */ + find_optimal_pairing(PLA, strategy); + break; + + case KEY_pairall: /* try all pairings !! */ + pair_all(PLA, strategy); + break; + + + +/******************** Simple cover operations ********************/ + + case KEY_echo: /* echo the PLA */ + break; + + case KEY_taut: /* tautology check */ + printf("ON-set is%sa tautology\n", + tautology(cube1list(PLA->F)) ? " " : " not "); + print_solution = FALSE; + break; + + case KEY_contain: /* single cube containment */ + PLA->F = sf_contain(PLA->F); + break; + + case KEY_intersect: /* cover intersection */ + PLA->F = cv_intersect(PLA->F, PLA1->F); + break; + + case KEY_union: /* cover union */ + PLA->F = sf_union(PLA->F, PLA1->F); + break; + + case KEY_disjoint: /* make cover disjoint */ + PLA->F = make_disjoint(PLA->F); + break; + + case KEY_dsharp: /* cover disjoint-sharp */ + PLA->F = cv_dsharp(PLA->F, PLA1->F); + break; + + case KEY_sharp: /* cover sharp */ + PLA->F = cv_sharp(PLA->F, PLA1->F); + break; + + case KEY_lexsort: /* lexical sort order */ + PLA->F = lex_sort(PLA->F); + break; + + case KEY_stats: /* print info on size */ + if (! summary) PLA_summary(PLA); + print_solution = FALSE; + break; + + case KEY_minterms: /* explode into minterms */ + if (first < 0 || first >= cube.num_vars) { + first = 0; + } + if (last < 0 || last >= cube.num_vars) { + last = cube.num_vars - 1; + } + PLA->F = sf_dupl(unravel_range(PLA->F, first, last)); + break; + + case KEY_d1merge: /* distance-1 merge */ + if (first < 0 || first >= cube.num_vars) { + first = 0; + } + if (last < 0 || last >= cube.num_vars) { + last = cube.num_vars - 1; + } + for(i = first; i <= last; i++) { + PLA->F = d1merge(PLA->F, i); + } + break; + + case KEY_d1merge_in: /* distance-1 merge inputs only */ + for(i = 0; i < cube.num_binary_vars; i++) { + PLA->F = d1merge(PLA->F, i); + } + break; + + case KEY_PLA_verify: /* check two PLAs for equivalence */ + EXECUTE(error = PLA_verify(PLA, PLA1), VERIFY_TIME, PLA->F, cost); + if (error) { + printf("PLA comparison failed; the PLA's are not equivalent\n"); + exit(1); + } else { + printf("PLA's compared equal\n"); + exit(0); + } + break; /* silly */ + + case KEY_verify: /* check two covers for equivalence */ + Fold = PLA->F; Dold = PLA->D; F = PLA1->F; + EXECUTE(error=verify(F, Fold, Dold), VERIFY_TIME, PLA->F, cost); + if (error) { + printf("PLA comparison failed; the PLA's are not equivalent\n"); + exit(1); + } else { + printf("PLA's compared equal\n"); + exit(0); + } + break; /* silly */ + + case KEY_check: /* check consistency */ + (void) check_consistency(PLA); + print_solution = FALSE; + break; + + case KEY_mapdc: /* compute don't care set */ + map_dcset(PLA); + out_type = FD_type; + break; + + case KEY_equiv: + find_equiv_outputs(PLA); + print_solution = FALSE; + break; + + case KEY_separate: /* remove PLA->D from PLA->F */ + PLA->F = complement(cube2list(PLA->D, PLA->R)); + break; + + case KEY_xor: { + pcover T1 = cv_intersect(PLA->F, PLA1->R); + pcover T2 = cv_intersect(PLA1->F, PLA->R); + free_cover(PLA->F); + PLA->F = sf_contain(sf_join(T1, T2)); + free_cover(T1); + free_cover(T2); + break; + } + + case KEY_fsm: { + disassemble_fsm(PLA, summary); + print_solution = FALSE; + break; + } + + case KEY_test: { + pcover T, E; + T = sf_join(PLA->D, PLA->R); + E = new_cover(10); + sf_free(PLA->F); + EXECUTE(PLA->F = complement(cube1list(T)), COMPL_TIME, PLA->F, cost); + EXECUTE(PLA->F = expand(PLA->F, T, FALSE), EXPAND_TIME, PLA->F, cost); + EXECUTE(PLA->F = irredundant(PLA->F, E), IRRED_TIME, PLA->F, cost); + sf_free(T); + T = sf_join(PLA->F, PLA->R); + EXECUTE(PLA->D = expand(PLA->D, T, FALSE), EXPAND_TIME, PLA->D, cost); + EXECUTE(PLA->D = irredundant(PLA->D, E), IRRED_TIME, PLA->D, cost); + sf_free(T); + sf_free(E); + break; + } + + + } + + /* Print a runtime summary if trace mode enabled */ + if (trace) { + runtime(); + } + + /* Print total runtime */ + if (summary || trace) { + print_trace(PLA->F, option_table[option].name, ptime()-start); + } + + /* Output the solution */ + if (print_solution) { + EXECUTE(fprint_pla(stdout, PLA, out_type), WRITE_TIME, PLA->F, cost); + } + + /* Crash and burn if there was a verify error */ + if (error) { + fatal("cover verification failed"); + } + + /* cleanup all used memory */ + free_PLA(PLA); + FREE(cube.part_size); + setdown_cube(); /* free the cube/cdata structure data */ + sf_cleanup(); /* free unused set structures */ + sm_cleanup(); /* sparse matrix cleanup */ + + exit(0); +} + + +getPLA(opt, argc, argv, option, PLA, out_type) +int opt; +int argc; +char *argv[]; +int option; +pPLA *PLA; +int out_type; +{ + FILE *fp; + int needs_dcset, needs_offset; + char *fname; + + if (opt >= argc) { + fp = stdin; + fname = "(stdin)"; + } else { + fname = argv[opt]; + if (strcmp(fname, "-") == 0) { + fp = stdin; + } else if ((fp = fopen(argv[opt], "r")) == NULL) { + (void) fprintf(stderr, "%s: Unable to open %s\n", argv[0], fname); + exit(1); + } + } + if (option_table[option].key == KEY_echo) { + needs_dcset = (out_type & D_type) != 0; + needs_offset = (out_type & R_type) != 0; + } else { + needs_dcset = option_table[option].needs_dcset; + needs_offset = option_table[option].needs_offset; + } + + if (read_pla(fp, needs_dcset, needs_offset, input_type, PLA) == EOF) { + (void) fprintf(stderr, "%s: Unable to find PLA on file %s\n", argv[0], fname); + exit(1); + } + (*PLA)->filename = util_strsav(fname); + filename = (*PLA)->filename; +/* (void) fclose(fp);*/ +/* hackto support -Dmany */ + last_fp = fp; +} + + +runtime() +{ + int i; + long total = 1, temp; + + for(i = 0; i < TIME_COUNT; i++) { + total += total_time[i]; + } + for(i = 0; i < TIME_COUNT; i++) { + if (total_calls[i] != 0) { + temp = 100 * total_time[i]; + printf("# %s\t%2d call(s) for %s (%2ld.%01ld%%)\n", + total_name[i], total_calls[i], print_time(total_time[i]), + temp/total, (10 * (temp%total)) / total); + } + } +} + + +init_runtime() +{ + total_name[READ_TIME] = "READ "; + total_name[WRITE_TIME] = "WRITE "; + total_name[COMPL_TIME] = "COMPL "; + total_name[REDUCE_TIME] = "REDUCE "; + total_name[EXPAND_TIME] = "EXPAND "; + total_name[ESSEN_TIME] = "ESSEN "; + total_name[IRRED_TIME] = "IRRED "; + total_name[GREDUCE_TIME] = "REDUCE_GASP"; + total_name[GEXPAND_TIME] = "EXPAND_GASP"; + total_name[GIRRED_TIME] = "IRRED_GASP "; + total_name[MV_REDUCE_TIME] ="MV_REDUCE "; + total_name[RAISE_IN_TIME] = "RAISE_IN "; + total_name[VERIFY_TIME] = "VERIFY "; + total_name[PRIMES_TIME] = "PRIMES "; + total_name[MINCOV_TIME] = "MINCOV "; +} + + +subcommands() +{ + int i, col; + printf(" "); + col = 16; + for(i = 0; option_table[i].name != 0; i++) { + if ((col + strlen(option_table[i].name) + 1) > 76) { + printf(",\n "); + col = 16; + } else if (i != 0) { + printf(", "); + } + printf("%s", option_table[i].name); + col += strlen(option_table[i].name) + 2; + } + printf("\n"); +} + + +usage() +{ + printf("%s\n\n", VERSION); + printf("SYNOPSIS: espresso [options] [file]\n\n"); + printf(" -d Enable debugging\n"); + printf(" -e[opt] Select espresso option:\n"); + printf(" fast, ness, nirr, nunwrap, onset, pos, strong,\n"); + printf(" eat, eatdots, kiss, random\n"); + printf(" -o[type] Select output format:\n"); + printf(" f, fd, fr, fdr, pleasure, eqntott, kiss, cons\n"); + printf(" -rn-m Select range for subcommands:\n"); + printf(" d1merge: first and last variables (0 ... m-1)\n"); + printf(" minterms: first and last variables (0 ... m-1)\n"); + printf(" opoall: first and last outputs (0 ... m-1)\n"); + printf(" -s Provide short execution summary\n"); + printf(" -t Provide longer execution trace\n"); + printf(" -x Suppress printing of solution\n"); + printf(" -v[type] Verbose debugging detail (-v '' for all)\n"); + printf(" -D[cmd] Execute subcommand 'cmd':\n"); + subcommands(); + printf(" -Sn Select strategy for subcommands:\n"); + printf(" opo: bit2=exact bit1=repeated bit0=skip sparse\n"); + printf(" opoall: 0=minimize, 1=exact\n"); + printf(" pair: 0=algebraic, 1=strongd, 2=espresso, 3=exact\n"); + printf(" pairall: 0=minimize, 1=exact, 2=opo\n"); + printf(" so_espresso: 0=minimize, 1=exact\n"); + printf(" so_both: 0=minimize, 1=exact\n"); +} + +/* + * Hack for backward compatibility (ACK! ) + */ + +backward_compatibility_hack(argc, argv, option, out_type) +int *argc; +char **argv; +int *option; +int *out_type; +{ + int i, j; + + /* Scan the argument list for something to do (default is ESPRESSO) */ + *option = 0; + for(i = 1; i < (*argc)-1; i++) { + if (strcmp(argv[i], "-do") == 0) { + for(j = 0; option_table[j].name != 0; j++) + if (strcmp(argv[i+1], option_table[j].name) == 0) { + *option = j; + delete_arg(argc, argv, i+1); + delete_arg(argc, argv, i); + break; + } + if (option_table[j].name == 0) { + (void) fprintf(stderr, + "espresso: bad keyword \"%s\" following -do\n",argv[i+1]); + exit(1); + } + break; + } + } + + for(i = 1; i < (*argc)-1; i++) { + if (strcmp(argv[i], "-out") == 0) { + for(j = 0; pla_types[j].key != 0; j++) + if (strcmp(pla_types[j].key+1, argv[i+1]) == 0) { + *out_type = pla_types[j].value; + delete_arg(argc, argv, i+1); + delete_arg(argc, argv, i); + break; + } + if (pla_types[j].key == 0) { + (void) fprintf(stderr, + "espresso: bad keyword \"%s\" following -out\n",argv[i+1]); + exit(1); + } + break; + } + } + + for(i = 1; i < (*argc); i++) { + if (argv[i][0] == '-') { + for(j = 0; esp_opt_table[j].name != 0; j++) { + if (strcmp(argv[i]+1, esp_opt_table[j].name) == 0) { + delete_arg(argc, argv, i); + *(esp_opt_table[j].variable) = esp_opt_table[j].value; + break; + } + } + } + } + + if (check_arg(argc, argv, "-fdr")) input_type = FDR_type; + if (check_arg(argc, argv, "-fr")) input_type = FR_type; + if (check_arg(argc, argv, "-f")) input_type = F_type; +} + + +/* delete_arg -- delete an argument from the argument list */ +delete_arg(argc, argv, num) +int *argc, num; +register char *argv[]; +{ + register int i; + (*argc)--; + for(i = num; i < *argc; i++) { + argv[i] = argv[i+1]; + } +} + + +/* check_arg -- scan argv for an argument, and return TRUE if found */ +bool check_arg(argc, argv, s) +int *argc; +register char *argv[], *s; +{ + register int i; + for(i = 1; i < *argc; i++) { + if (strcmp(argv[i], s) == 0) { + delete_arg(argc, argv, i); + return TRUE; + } + } + return FALSE; +} diff --git a/src/misc/espresso/main.h b/src/misc/espresso/main.h new file mode 100644 index 00000000..00657f39 --- /dev/null +++ b/src/misc/espresso/main.h @@ -0,0 +1,122 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +enum keys { + KEY_ESPRESSO, KEY_PLA_verify, KEY_check, KEY_contain, KEY_d1merge, + KEY_disjoint, KEY_dsharp, KEY_echo, KEY_essen, KEY_exact, KEY_expand, + KEY_gasp, KEY_intersect, KEY_irred, KEY_lexsort, KEY_make_sparse, + KEY_map, KEY_mapdc, KEY_minterms, KEY_opo, KEY_opoall, + KEY_pair, KEY_pairall, KEY_primes, KEY_qm, KEY_reduce, KEY_sharp, + KEY_simplify, KEY_so, KEY_so_both, KEY_stats, KEY_super_gasp, KEY_taut, + KEY_test, KEY_equiv, KEY_union, KEY_verify, KEY_MANY_ESPRESSO, + KEY_separate, KEY_xor, KEY_d1merge_in, KEY_fsm, + KEY_unknown +}; + +/* Lookup table for program options */ +struct { + char *name; + enum keys key; + int num_plas; + bool needs_offset; + bool needs_dcset; +} option_table [] = { + /* ways to minimize functions */ + "ESPRESSO", KEY_ESPRESSO, 1, TRUE, TRUE, /* must be first */ + "many", KEY_MANY_ESPRESSO, 1, TRUE, TRUE, + "exact", KEY_exact, 1, TRUE, TRUE, + "qm", KEY_qm, 1, TRUE, TRUE, + "single_output", KEY_so, 1, TRUE, TRUE, + "so", KEY_so, 1, TRUE, TRUE, + "so_both", KEY_so_both, 1, TRUE, TRUE, + "simplify", KEY_simplify, 1, FALSE, FALSE, + "echo", KEY_echo, 1, FALSE, FALSE, + + /* output phase assignment and assignment of inputs to two-bit decoders */ + "opo", KEY_opo, 1, TRUE, TRUE, + "opoall", KEY_opoall, 1, TRUE, TRUE, + "pair", KEY_pair, 1, TRUE, TRUE, + "pairall", KEY_pairall, 1, TRUE, TRUE, + + /* Ways to check covers */ + "check", KEY_check, 1, TRUE, TRUE, + "stats", KEY_stats, 1, FALSE, FALSE, + "verify", KEY_verify, 2, FALSE, TRUE, + "PLAverify", KEY_PLA_verify, 2, FALSE, TRUE, + + /* hacks */ + "equiv", KEY_equiv, 1, TRUE, TRUE, + "map", KEY_map, 1, FALSE, FALSE, + "mapdc", KEY_mapdc, 1, FALSE, FALSE, + "fsm", KEY_fsm, 1, FALSE, TRUE, + + /* the basic boolean operations on covers */ + "contain", KEY_contain, 1, FALSE, FALSE, + "d1merge", KEY_d1merge, 1, FALSE, FALSE, + "d1merge_in", KEY_d1merge_in, 1, FALSE, FALSE, + "disjoint", KEY_disjoint, 1, TRUE, FALSE, + "dsharp", KEY_dsharp, 2, FALSE, FALSE, + "intersect", KEY_intersect, 2, FALSE, FALSE, + "minterms", KEY_minterms, 1, FALSE, FALSE, + "primes", KEY_primes, 1, FALSE, TRUE, + "separate", KEY_separate, 1, TRUE, TRUE, + "sharp", KEY_sharp, 2, FALSE, FALSE, + "union", KEY_union, 2, FALSE, FALSE, + "xor", KEY_xor, 2, TRUE, TRUE, + + /* debugging only -- call each step of the espresso algorithm */ + "essen", KEY_essen, 1, FALSE, TRUE, + "expand", KEY_expand, 1, TRUE, FALSE, + "gasp", KEY_gasp, 1, TRUE, TRUE, + "irred", KEY_irred, 1, FALSE, TRUE, + "make_sparse", KEY_make_sparse, 1, TRUE, TRUE, + "reduce", KEY_reduce, 1, FALSE, TRUE, + "taut", KEY_taut, 1, FALSE, FALSE, + "super_gasp", KEY_super_gasp, 1, TRUE, TRUE, + "lexsort", KEY_lexsort, 1, FALSE, FALSE, + "test", KEY_test, 1, TRUE, TRUE, + 0, KEY_unknown, 0, FALSE, FALSE /* must be last */ +}; + + +struct { + char *name; + int value; +} debug_table[] = { + "", EXPAND + ESSEN + IRRED + REDUCE + SPARSE + GASP + SHARP + MINCOV, + "compl", COMPL, "essen", ESSEN, + "expand", EXPAND, "expand1", EXPAND1|EXPAND, + "irred", IRRED, "irred1", IRRED1|IRRED, + "reduce", REDUCE, "reduce1", REDUCE1|REDUCE, + "mincov", MINCOV, "mincov1", MINCOV1|MINCOV, + "sparse", SPARSE, "sharp", SHARP, + "taut", TAUT, "gasp", GASP, + "exact", EXACT, + 0, +}; + + +struct { + char *name; + int *variable; + int value; +} esp_opt_table[] = { + "eat", &echo_comments, FALSE, + "eatdots", &echo_unknown_commands, FALSE, + "fast", &single_expand, TRUE, + "kiss", &kiss, TRUE, + "ness", &remove_essential, FALSE, + "nirr", &force_irredundant, FALSE, + "nunwrap", &unwrap_onset, FALSE, + "onset", &recompute_onset, TRUE, + "pos", &pos, TRUE, + "random", &use_random_order, TRUE, + "strong", &use_super_gasp, TRUE, + 0, +}; diff --git a/src/misc/espresso/map.c b/src/misc/espresso/map.c new file mode 100644 index 00000000..5ccf264c --- /dev/null +++ b/src/misc/espresso/map.c @@ -0,0 +1,115 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +#include "espresso.h" + +static pcube Gcube; +static pset Gminterm; + +pset minterms(T) +pcover T; +{ + int size, var; + register pcube last; + + size = 1; + for(var = 0; var < cube.num_vars; var++) + size *= cube.part_size[var]; + Gminterm = set_new(size); + + foreach_set(T, last, Gcube) + explode(cube.num_vars-1, 0); + + return Gminterm; +} + + +void explode(var, z) +int var, z; +{ + int i, last = cube.last_part[var]; + for(i=cube.first_part[var], z *= cube.part_size[var]; i<=last; i++, z++) + if (is_in_set(Gcube, i)) + if (var == 0) + set_insert(Gminterm, z); + else + explode(var-1, z); +} + + +static int mapindex[16][16] = { + 0, 1, 3, 2, 16, 17, 19, 18, 80, 81, 83, 82, 64, 65, 67, 66, + 4, 5, 7, 6, 20, 21, 23, 22, 84, 85, 87, 86, 68, 69, 71, 70, + 12, 13, 15, 14, 28, 29, 31, 30, 92, 93, 95, 94, 76, 77, 79, 78, + 8, 9, 11, 10, 24, 25, 27, 26, 88, 89, 91, 90, 72, 73, 75, 74, + + 32, 33, 35, 34, 48, 49, 51, 50, 112,113,115,114, 96, 97, 99, 98, + 36, 37, 39, 38, 52, 53, 55, 54, 116,117,119,118, 100,101,103,102, + 44, 45, 47, 46, 60, 61, 63, 62, 124,125,127,126, 108,109,111,110, + 40, 41, 43, 42, 56, 57, 59, 58, 120,121,123,122, 104,105,107,106, + + + 160,161,163,162, 176,177,179,178, 240,241,243,242, 224,225,227,226, + 164,165,167,166, 180,181,183,182, 244,245,247,246, 228,229,231,230, + 172,173,175,174, 188,189,191,190, 252,253,255,254, 236,237,239,238, + 168,169,171,170, 184,185,187,186, 248,249,251,250, 232,233,235,234, + + 128,129,131,130, 144,145,147,146, 208,209,211,210, 192,193,195,194, + 132,133,135,134, 148,149,151,150, 212,213,215,214, 196,197,199,198, + 140,141,143,142, 156,157,159,158, 220,221,223,222, 204,205,207,206, + 136,137,139,138, 152,153,155,154, 216,217,219,218, 200,201,203,202 +}; + +#define POWER2(n) (1 << n) +void map(T) +pcover T; +{ + int j, k, l, other_input_offset, output_offset, outnum, ind; + int largest_input_ind, numout; + char c; + pset m; + bool some_output; + + m = minterms(T); + largest_input_ind = POWER2(cube.num_binary_vars); + numout = cube.part_size[cube.num_vars-1]; + + for(outnum = 0; outnum < numout; outnum++) { + output_offset = outnum * largest_input_ind; + printf("\n\nOutput space # %d\n", outnum); + for(l = 0; l <= MAX(cube.num_binary_vars - 8, 0); l++) { + other_input_offset = l * 256; + for(k = 0; k < 16; k++) { + some_output = FALSE; + for(j = 0; j < 16; j++) { + ind = mapindex[k][j] + other_input_offset; + if (ind < largest_input_ind) { + c = is_in_set(m, ind+output_offset) ? '1' : '.'; + putchar(c); + some_output = TRUE; + } + if ((j+1)%4 == 0) + putchar(' '); + if ((j+1)%8 == 0) + printf(" "); + } + if (some_output) + putchar('\n'); + if ((k+1)%4 == 0) { + if (k != 15 && mapindex[k+1][0] >= largest_input_ind) + break; + putchar('\n'); + } + if ((k+1)%8 == 0) + putchar('\n'); + } + } + } + set_free(m); +} diff --git a/src/misc/espresso/matrix.c b/src/misc/espresso/matrix.c new file mode 100644 index 00000000..747fe54f --- /dev/null +++ b/src/misc/espresso/matrix.c @@ -0,0 +1,574 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +//#include "port.h" +#include "sparse_int.h" + +/* + * free-lists are only used if 'FAST_AND_LOOSE' is set; this is because + * we lose the debugging capability of libmm_t which trashes objects when + * they are free'd. However, FAST_AND_LOOSE is much faster if matrices + * are created and freed frequently. + */ + +#ifdef FAST_AND_LOOSE +sm_element *sm_element_freelist; +sm_row *sm_row_freelist; +sm_col *sm_col_freelist; +#endif + + +sm_matrix * +sm_alloc() +{ + register sm_matrix *A; + + A = ALLOC(sm_matrix, 1); + A->rows = NIL(sm_row *); + A->cols = NIL(sm_col *); + A->nrows = A->ncols = 0; + A->rows_size = A->cols_size = 0; + A->first_row = A->last_row = NIL(sm_row); + A->first_col = A->last_col = NIL(sm_col); + A->user_word = NIL(char); /* for our user ... */ + return A; +} + + +sm_matrix * +sm_alloc_size(row, col) +int row, col; +{ + register sm_matrix *A; + + A = sm_alloc(); + sm_resize(A, row, col); + return A; +} + + +void +sm_free(A) +sm_matrix *A; +{ +#ifdef FAST_AND_LOOSE + register sm_row *prow; + + if (A->first_row != 0) { + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + /* add the elements to the free list of elements */ + prow->last_col->next_col = sm_element_freelist; + sm_element_freelist = prow->first_col; + } + + /* Add the linked list of rows to the row-free-list */ + A->last_row->next_row = sm_row_freelist; + sm_row_freelist = A->first_row; + + /* Add the linked list of cols to the col-free-list */ + A->last_col->next_col = sm_col_freelist; + sm_col_freelist = A->first_col; + } +#else + register sm_row *prow, *pnext_row; + register sm_col *pcol, *pnext_col; + + for(prow = A->first_row; prow != 0; prow = pnext_row) { + pnext_row = prow->next_row; + sm_row_free(prow); + } + for(pcol = A->first_col; pcol != 0; pcol = pnext_col) { + pnext_col = pcol->next_col; + pcol->first_row = pcol->last_row = NIL(sm_element); + sm_col_free(pcol); + } +#endif + + /* Free the arrays to map row/col numbers into pointers */ + FREE(A->rows); + FREE(A->cols); + FREE(A); +} + + +sm_matrix * +sm_dup(A) +sm_matrix *A; +{ + register sm_row *prow; + register sm_element *p; + register sm_matrix *B; + + B = sm_alloc(); + if (A->last_row != 0) { + sm_resize(B, A->last_row->row_num, A->last_col->col_num); + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + for(p = prow->first_col; p != 0; p = p->next_col) { + (void) sm_insert(B, p->row_num, p->col_num); + } + } + } + return B; +} + + +void +sm_resize(A, row, col) +register sm_matrix *A; +int row, col; +{ + register int i, new_size; + + if (row >= A->rows_size) { + new_size = MAX(A->rows_size*2, row+1); + A->rows = REALLOC(sm_row *, A->rows, new_size); + for(i = A->rows_size; i < new_size; i++) { + A->rows[i] = NIL(sm_row); + } + A->rows_size = new_size; + } + + if (col >= A->cols_size) { + new_size = MAX(A->cols_size*2, col+1); + A->cols = REALLOC(sm_col *, A->cols, new_size); + for(i = A->cols_size; i < new_size; i++) { + A->cols[i] = NIL(sm_col); + } + A->cols_size = new_size; + } +} + + +/* + * insert -- insert a value into the matrix + */ +sm_element * +sm_insert(A, row, col) +register sm_matrix *A; +register int row, col; +{ + register sm_row *prow; + register sm_col *pcol; + register sm_element *element; + sm_element *save_element; + + if (row >= A->rows_size || col >= A->cols_size) { + sm_resize(A, row, col); + } + + prow = A->rows[row]; + if (prow == NIL(sm_row)) { + prow = A->rows[row] = sm_row_alloc(); + prow->row_num = row; + sorted_insert(sm_row, A->first_row, A->last_row, A->nrows, + next_row, prev_row, row_num, row, prow); + } + + pcol = A->cols[col]; + if (pcol == NIL(sm_col)) { + pcol = A->cols[col] = sm_col_alloc(); + pcol->col_num = col; + sorted_insert(sm_col, A->first_col, A->last_col, A->ncols, + next_col, prev_col, col_num, col, pcol); + } + + /* get a new item, save its address */ + sm_element_alloc(element); + save_element = element; + + /* insert it into the row list */ + sorted_insert(sm_element, prow->first_col, prow->last_col, + prow->length, next_col, prev_col, col_num, col, element); + + /* if it was used, also insert it into the column list */ + if (element == save_element) { + sorted_insert(sm_element, pcol->first_row, pcol->last_row, + pcol->length, next_row, prev_row, row_num, row, element); + } else { + /* otherwise, it was already in matrix -- free element we allocated */ + sm_element_free(save_element); + } + return element; +} + + +sm_element * +sm_find(A, rownum, colnum) +sm_matrix *A; +int rownum, colnum; +{ + sm_row *prow; + sm_col *pcol; + + prow = sm_get_row(A, rownum); + if (prow == NIL(sm_row)) { + return NIL(sm_element); + } else { + pcol = sm_get_col(A, colnum); + if (pcol == NIL(sm_col)) { + return NIL(sm_element); + } + if (prow->length < pcol->length) { + return sm_row_find(prow, colnum); + } else { + return sm_col_find(pcol, rownum); + } + } +} + + +void +sm_remove(A, rownum, colnum) +sm_matrix *A; +int rownum, colnum; +{ + sm_remove_element(A, sm_find(A, rownum, colnum)); +} + + + +void +sm_remove_element(A, p) +register sm_matrix *A; +register sm_element *p; +{ + register sm_row *prow; + register sm_col *pcol; + + if (p == 0) return; + + /* Unlink the element from its row */ + prow = sm_get_row(A, p->row_num); + dll_unlink(p, prow->first_col, prow->last_col, + next_col, prev_col, prow->length); + + /* if no more elements in the row, discard the row header */ + if (prow->first_col == NIL(sm_element)) { + sm_delrow(A, p->row_num); + } + + /* Unlink the element from its column */ + pcol = sm_get_col(A, p->col_num); + dll_unlink(p, pcol->first_row, pcol->last_row, + next_row, prev_row, pcol->length); + + /* if no more elements in the column, discard the column header */ + if (pcol->first_row == NIL(sm_element)) { + sm_delcol(A, p->col_num); + } + + sm_element_free(p); +} + +void +sm_delrow(A, i) +sm_matrix *A; +int i; +{ + register sm_element *p, *pnext; + sm_col *pcol; + sm_row *prow; + + prow = sm_get_row(A, i); + if (prow != NIL(sm_row)) { + /* walk across the row */ + for(p = prow->first_col; p != 0; p = pnext) { + pnext = p->next_col; + + /* unlink the item from the column (and delete it) */ + pcol = sm_get_col(A, p->col_num); + sm_col_remove_element(pcol, p); + + /* discard the column if it is now empty */ + if (pcol->first_row == NIL(sm_element)) { + sm_delcol(A, pcol->col_num); + } + } + + /* discard the row -- we already threw away the elements */ + A->rows[i] = NIL(sm_row); + dll_unlink(prow, A->first_row, A->last_row, + next_row, prev_row, A->nrows); + prow->first_col = prow->last_col = NIL(sm_element); + sm_row_free(prow); + } +} + +void +sm_delcol(A, i) +sm_matrix *A; +int i; +{ + register sm_element *p, *pnext; + sm_row *prow; + sm_col *pcol; + + pcol = sm_get_col(A, i); + if (pcol != NIL(sm_col)) { + /* walk down the column */ + for(p = pcol->first_row; p != 0; p = pnext) { + pnext = p->next_row; + + /* unlink the element from the row (and delete it) */ + prow = sm_get_row(A, p->row_num); + sm_row_remove_element(prow, p); + + /* discard the row if it is now empty */ + if (prow->first_col == NIL(sm_element)) { + sm_delrow(A, prow->row_num); + } + } + + /* discard the column -- we already threw away the elements */ + A->cols[i] = NIL(sm_col); + dll_unlink(pcol, A->first_col, A->last_col, + next_col, prev_col, A->ncols); + pcol->first_row = pcol->last_row = NIL(sm_element); + sm_col_free(pcol); + } +} + +void +sm_copy_row(dest, dest_row, prow) +register sm_matrix *dest; +int dest_row; +sm_row *prow; +{ + register sm_element *p; + + for(p = prow->first_col; p != 0; p = p->next_col) { + (void) sm_insert(dest, dest_row, p->col_num); + } +} + + +void +sm_copy_col(dest, dest_col, pcol) +register sm_matrix *dest; +int dest_col; +sm_col *pcol; +{ + register sm_element *p; + + for(p = pcol->first_row; p != 0; p = p->next_row) { + (void) sm_insert(dest, dest_col, p->row_num); + } +} + + +sm_row * +sm_longest_row(A) +sm_matrix *A; +{ + register sm_row *large_row, *prow; + register int max_length; + + max_length = 0; + large_row = NIL(sm_row); + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + if (prow->length > max_length) { + max_length = prow->length; + large_row = prow; + } + } + return large_row; +} + + +sm_col * +sm_longest_col(A) +sm_matrix *A; +{ + register sm_col *large_col, *pcol; + register int max_length; + + max_length = 0; + large_col = NIL(sm_col); + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) { + if (pcol->length > max_length) { + max_length = pcol->length; + large_col = pcol; + } + } + return large_col; +} + +int +sm_num_elements(A) +sm_matrix *A; +{ + register sm_row *prow; + register int num; + + num = 0; + sm_foreach_row(A, prow) { + num += prow->length; + } + return num; +} + +int +sm_read(fp, A) +FILE *fp; +sm_matrix **A; +{ + int i, j, err; + + *A = sm_alloc(); + while (! feof(fp)) { + err = fscanf(fp, "%d %d", &i, &j); + if (err == EOF) { + return 1; + } else if (err != 2) { + return 0; + } + (void) sm_insert(*A, i, j); + } + return 1; +} + + +int +sm_read_compressed(fp, A) +FILE *fp; +sm_matrix **A; +{ + int i, j, k, nrows, ncols; + unsigned long x; + + *A = sm_alloc(); + if (fscanf(fp, "%d %d", &nrows, &ncols) != 2) { + return 0; + } + sm_resize(*A, nrows, ncols); + + for(i = 0; i < nrows; i++) { + if (fscanf(fp, "%lx", &x) != 1) { + return 0; + } + for(j = 0; j < ncols; j += 32) { + if (fscanf(fp, "%lx", &x) != 1) { + return 0; + } + for(k = j; x != 0; x >>= 1, k++) { + if (x & 1) { + (void) sm_insert(*A, i, k); + } + } + } + } + return 1; +} + + +void +sm_write(fp, A) +FILE *fp; +sm_matrix *A; +{ + register sm_row *prow; + register sm_element *p; + + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + for(p = prow->first_col; p != 0; p = p->next_col) { + (void) fprintf(fp, "%d %d\n", p->row_num, p->col_num); + } + } +} + +void +sm_print(fp, A) +FILE *fp; +sm_matrix *A; +{ + register sm_row *prow; + register sm_col *pcol; + int c; + + if (A->last_col->col_num >= 100) { + (void) fprintf(fp, " "); + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) { + (void) fprintf(fp, "%d", (pcol->col_num / 100)%10); + } + putc('\n', fp); + } + + if (A->last_col->col_num >= 10) { + (void) fprintf(fp, " "); + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) { + (void) fprintf(fp, "%d", (pcol->col_num / 10)%10); + } + putc('\n', fp); + } + + (void) fprintf(fp, " "); + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) { + (void) fprintf(fp, "%d", pcol->col_num % 10); + } + putc('\n', fp); + + (void) fprintf(fp, " "); + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) { + (void) fprintf(fp, "-"); + } + putc('\n', fp); + + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + (void) fprintf(fp, "%3d:", prow->row_num); + + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) { + c = sm_row_find(prow, pcol->col_num) ? '1' : '.'; + putc(c, fp); + } + putc('\n', fp); + } +} + + +void +sm_dump(A, s, max) +sm_matrix *A; +char *s; +int max; +{ + FILE *fp = stdout; + + (void) fprintf(fp, "%s %d rows by %d cols\n", s, A->nrows, A->ncols); + if (A->nrows < max) { + sm_print(fp, A); + } +} + +void +sm_cleanup() +{ +#ifdef FAST_AND_LOOSE + register sm_element *p, *pnext; + register sm_row *prow, *pnextrow; + register sm_col *pcol, *pnextcol; + + for(p = sm_element_freelist; p != 0; p = pnext) { + pnext = p->next_col; + FREE(p); + } + sm_element_freelist = 0; + + for(prow = sm_row_freelist; prow != 0; prow = pnextrow) { + pnextrow = prow->next_row; + FREE(prow); + } + sm_row_freelist = 0; + + for(pcol = sm_col_freelist; pcol != 0; pcol = pnextcol) { + pnextcol = pcol->next_col; + FREE(pcol); + } + sm_col_freelist = 0; +#endif +} diff --git a/src/misc/espresso/mincov.c b/src/misc/espresso/mincov.c new file mode 100644 index 00000000..ee18a3f1 --- /dev/null +++ b/src/misc/espresso/mincov.c @@ -0,0 +1,378 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +#include "mincov_int.h" + +/* + * mincov.c + */ + +#define USE_GIMPEL +#define USE_INDEP_SET + +static int select_column(); +static void select_essential(); +static int verify_cover(); + +#define fail(why) {\ + (void) fprintf(stderr, "Fatal error: file %s, line %d\n%s\n",\ + __FILE__, __LINE__, why);\ + (void) fflush(stdout);\ + abort();\ +} + +sm_row * +sm_minimum_cover(A, weight, heuristic, debug_level) +sm_matrix *A; +int *weight; +int heuristic; /* set to 1 for a heuristic covering */ +int debug_level; /* how deep in the recursion to provide info */ +{ + stats_t stats; + solution_t *best, *select; + sm_row *prow, *sol; + sm_col *pcol; + sm_matrix *dup_A; + int nelem, bound; + double sparsity; + + /* Avoid sillyness */ + if (A->nrows <= 0) { + return sm_row_alloc(); /* easy to cover */ + } + + /* Initialize debugging structure */ + stats.start_time = util_cpu_time(); + stats.debug = debug_level > 0; + stats.max_print_depth = debug_level; + stats.max_depth = -1; + stats.nodes = 0; + stats.component = stats.comp_count = 0; + stats.gimpel = stats.gimpel_count = 0; + stats.no_branching = heuristic != 0; + stats.lower_bound = -1; + + /* Check the matrix sparsity */ + nelem = 0; + sm_foreach_row(A, prow) { + nelem += prow->length; + } + sparsity = (double) nelem / (double) (A->nrows * A->ncols); + + /* Determine an upper bound on the solution */ + bound = 1; + sm_foreach_col(A, pcol) { + bound += WEIGHT(weight, pcol->col_num); + } + + /* Perform the covering */ + select = solution_alloc(); + dup_A = sm_dup(A); + best = sm_mincov(dup_A, select, weight, 0, bound, 0, &stats); + sm_free(dup_A); + solution_free(select); + + if (stats.debug) { + if (stats.no_branching) { + (void) printf("**** heuristic covering ...\n"); + (void) printf("lower bound = %d\n", stats.lower_bound); + } + (void) printf("matrix = %d by %d with %d elements (%4.3f%%)\n", + A->nrows, A->ncols, nelem, sparsity * 100.0); + (void) printf("cover size = %d elements\n", best->row->length); + (void) printf("cover cost = %d\n", best->cost); + (void) printf("time = %s\n", + util_print_time(util_cpu_time() - stats.start_time)); + (void) printf("components = %d\n", stats.comp_count); + (void) printf("gimpel = %d\n", stats.gimpel_count); + (void) printf("nodes = %d\n", stats.nodes); + (void) printf("max_depth = %d\n", stats.max_depth); + } + + sol = sm_row_dup(best->row); + if (! verify_cover(A, sol)) { + fail("mincov: internal error -- cover verification failed\n"); + } + solution_free(best); + return sol; +} + +/* + * Find the best cover for 'A' (given that 'select' already selected); + * + * - abort search if a solution cannot be found which beats 'bound' + * + * - if any solution meets 'lower_bound', then it is the optimum solution + * and can be returned without further work. + */ + +solution_t * +sm_mincov(A, select, weight, lb, bound, depth, stats) +sm_matrix *A; +solution_t *select; +int *weight; +int lb; +int bound; +int depth; +stats_t *stats; +{ + sm_matrix *A1, *A2, *L, *R; + sm_element *p; + solution_t *select1, *select2, *best, *best1, *best2, *indep; + int pick, lb_new, debug; + + /* Start out with some debugging information */ + stats->nodes++; + if (depth > stats->max_depth) stats->max_depth = depth; + debug = stats->debug && (depth <= stats->max_print_depth); + + /* Apply row dominance, column dominance, and select essentials */ + select_essential(A, select, weight, bound); + if (select->cost >= bound) { + return NIL(solution_t); + } + + /* See if gimpel's reduction technique applies ... */ +#ifdef USE_GIMPEL + if ( weight == NIL(int)) { /* hack until we fix it */ + if (gimpel_reduce(A, select, weight, lb, bound, depth, stats, &best)) { + return best; + } + } +#endif + +#ifdef USE_INDEP_SET + /* Determine bound from here to final solution using independent-set */ + indep = sm_maximal_independent_set(A, weight); + + /* make sure the lower bound is monotonically increasing */ + lb_new = MAX(select->cost + indep->cost, lb); + pick = select_column(A, weight, indep); + solution_free(indep); +#else + lb_new = select->cost + (A->nrows > 0); + pick = select_column(A, weight, NIL(solution_t)); +#endif + + if (depth == 0) { + stats->lower_bound = lb_new + stats->gimpel; + } + + if (debug) { + (void) printf("ABSMIN[%2d]%s", depth, stats->component ? "*" : " "); + (void) printf(" %3dx%3d sel=%3d bnd=%3d lb=%3d %12s ", + A->nrows, A->ncols, select->cost + stats->gimpel, + bound + stats->gimpel, lb_new + stats->gimpel, + util_print_time(util_cpu_time()-stats->start_time)); + } + + /* Check for bounding based on no better solution possible */ + if (lb_new >= bound) { + if (debug) (void) printf("bounded\n"); + best = NIL(solution_t); + + + /* Check for new best solution */ + } else if (A->nrows == 0) { + best = solution_dup(select); + if (debug) (void) printf("BEST\n"); + if (stats->debug && stats->component == 0) { + (void) printf("new 'best' solution %d at level %d (time is %s)\n", + best->cost + stats->gimpel, depth, + util_print_time(util_cpu_time() - stats->start_time)); + } + + + /* Check for a partition of the problem */ + } else if (sm_block_partition(A, &L, &R)) { + /* Make L the smaller problem */ + if (L->ncols > R->ncols) { + A1 = L; + L = R; + R = A1; + } + if (debug) (void) printf("comp %d %d\n", L->nrows, R->nrows); + stats->comp_count++; + + /* Solve problem for L */ + select1 = solution_alloc(); + stats->component++; + best1 = sm_mincov(L, select1, weight, 0, + bound-select->cost, depth+1, stats); + stats->component--; + solution_free(select1); + sm_free(L); + + /* Add best solution to the selected set */ + if (best1 == NIL(solution_t)) { + best = NIL(solution_t); + } else { + for(p = best1->row->first_col; p != 0; p = p->next_col) { + solution_add(select, weight, p->col_num); + } + solution_free(best1); + + /* recur for the remaining block */ + best = sm_mincov(R, select, weight, lb_new, bound, depth+1, stats); + } + sm_free(R); + + /* We've tried as hard as possible, but now we must split and recur */ + } else { + if (debug) (void) printf("pick=%d\n", pick); + + /* Assume we choose this column to be in the covering set */ + A1 = sm_dup(A); + select1 = solution_dup(select); + solution_accept(select1, A1, weight, pick); + best1 = sm_mincov(A1, select1, weight, lb_new, bound, depth+1, stats); + solution_free(select1); + sm_free(A1); + + /* Update the upper bound if we found a better solution */ + if (best1 != NIL(solution_t) && bound > best1->cost) { + bound = best1->cost; + } + + /* See if this is a heuristic covering (no branching) */ + if (stats->no_branching) { + return best1; + } + + /* Check for reaching lower bound -- if so, don't actually branch */ + if (best1 != NIL(solution_t) && best1->cost == lb_new) { + return best1; + } + + /* Now assume we cannot have that column */ + A2 = sm_dup(A); + select2 = solution_dup(select); + solution_reject(select2, A2, weight, pick); + best2 = sm_mincov(A2, select2, weight, lb_new, bound, depth+1, stats); + solution_free(select2); + sm_free(A2); + + best = solution_choose_best(best1, best2); + } + + return best; +} + +static int +select_column(A, weight, indep) +sm_matrix *A; +int *weight; +solution_t *indep; +{ + register sm_col *pcol; + register sm_row *prow, *indep_cols; + register sm_element *p, *p1; + double w, best; + int best_col; + + indep_cols = sm_row_alloc(); + if (indep != NIL(solution_t)) { + /* Find which columns are in the independent sets */ + for(p = indep->row->first_col; p != 0; p = p->next_col) { + prow = sm_get_row(A, p->col_num); + for(p1 = prow->first_col; p1 != 0; p1 = p1->next_col) { + (void) sm_row_insert(indep_cols, p1->col_num); + } + } + } else { + /* select out of all columns */ + sm_foreach_col(A, pcol) { + (void) sm_row_insert(indep_cols, pcol->col_num); + } + } + + /* Find the best column */ + best_col = -1; + best = -1; + + /* Consider only columns which are in some independent row */ + sm_foreach_row_element(indep_cols, p1) { + pcol = sm_get_col(A, p1->col_num); + + /* Compute the total 'value' of all things covered by the column */ + w = 0.0; + for(p = pcol->first_row; p != 0; p = p->next_row) { + prow = sm_get_row(A, p->row_num); + w += 1.0 / ((double) prow->length - 1.0); + } + + /* divide this by the relative cost of choosing this column */ + w = w / (double) WEIGHT(weight, pcol->col_num); + + /* maximize this ratio */ + if (w > best) { + best_col = pcol->col_num; + best = w; + } + } + + sm_row_free(indep_cols); + return best_col; +} + +static void +select_essential(A, select, weight, bound) +sm_matrix *A; +solution_t *select; +int *weight; +int bound; /* must beat this solution */ +{ + register sm_element *p; + register sm_row *prow, *essen; + int delcols, delrows, essen_count; + + do { + /* Check for dominated columns */ + delcols = sm_col_dominance(A, weight); + + /* Find the rows with only 1 element (the essentials) */ + essen = sm_row_alloc(); + sm_foreach_row(A, prow) { + if (prow->length == 1) { + (void) sm_row_insert(essen, prow->first_col->col_num); + } + } + + /* Select all of the elements */ + sm_foreach_row_element(essen, p) { + solution_accept(select, A, weight, p->col_num); + /* Make sure solution still looks good */ + if (select->cost >= bound) { + sm_row_free(essen); + return; + } + } + essen_count = essen->length; + sm_row_free(essen); + + /* Check for dominated rows */ + delrows = sm_row_dominance(A); + + } while (delcols > 0 || delrows > 0 || essen_count > 0); +} + +static int +verify_cover(A, cover) +sm_matrix *A; +sm_row *cover; +{ + sm_row *prow; + + sm_foreach_row(A, prow) { + if (! sm_row_intersects(prow, cover)) { + return 0; + } + } + return 1; +} diff --git a/src/misc/espresso/mincov.h b/src/misc/espresso/mincov.h new file mode 100644 index 00000000..95310774 --- /dev/null +++ b/src/misc/espresso/mincov.h @@ -0,0 +1,11 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +/* exported */ +extern sm_row *sm_minimum_cover(); diff --git a/src/misc/espresso/mincov_int.h b/src/misc/espresso/mincov_int.h new file mode 100644 index 00000000..e81850f2 --- /dev/null +++ b/src/misc/espresso/mincov_int.h @@ -0,0 +1,55 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +//#include "port.h" +//#include "utility.h" +#include "sparse.h" +#include "mincov.h" + +#include "util_hack.h" // added + + +typedef struct stats_struct stats_t; +struct stats_struct { + int debug; /* 1 if debugging is enabled */ + int max_print_depth; /* dump stats for levels up to this level */ + int max_depth; /* deepest the recursion has gone */ + int nodes; /* total nodes visited */ + int component; /* currently solving a component */ + int comp_count; /* number of components detected */ + int gimpel_count; /* number of times Gimpel reduction applied */ + int gimpel; /* currently inside Gimpel reduction */ + long start_time; /* cpu time when the covering started */ + int no_branching; + int lower_bound; +}; + + + +typedef struct solution_struct solution_t; +struct solution_struct { + sm_row *row; + int cost; +}; + + +extern solution_t *solution_alloc(); +extern void solution_free(); +extern solution_t *solution_dup(); +extern void solution_accept(); +extern void solution_reject(); +extern void solution_add(); +extern solution_t *solution_choose_best(); + +extern solution_t *sm_maximal_independent_set(); +extern solution_t *sm_mincov(); +extern int gimpel_reduce(); + + +#define WEIGHT(weight, col) (weight == NIL(int) ? 1 : weight[col]) diff --git a/src/misc/espresso/module.make b/src/misc/espresso/module.make new file mode 100644 index 00000000..53ce982a --- /dev/null +++ b/src/misc/espresso/module.make @@ -0,0 +1,39 @@ +SRC += src/misc/espresso/cofactor.c \ + src/misc/espresso/cols.c \ + src/misc/espresso/compl.c \ + src/misc/espresso/contain.c \ + src/misc/espresso/cubehack.c \ + src/misc/espresso/cubestr.c \ + src/misc/espresso/cvrin.c \ + src/misc/espresso/cvrm.c \ + src/misc/espresso/cvrmisc.c \ + src/misc/espresso/cvrout.c \ + src/misc/espresso/dominate.c \ + src/misc/espresso/equiv.c \ + src/misc/espresso/espresso.c \ + src/misc/espresso/essen.c \ + src/misc/espresso/exact.c \ + src/misc/espresso/expand.c \ + src/misc/espresso/gasp.c \ + src/misc/espresso/gimpel.c \ + src/misc/espresso/globals.c \ + src/misc/espresso/hack.c \ + src/misc/espresso/indep.c \ + src/misc/espresso/irred.c \ + src/misc/espresso/map.c \ + src/misc/espresso/matrix.c \ + src/misc/espresso/mincov.c \ + src/misc/espresso/opo.c \ + src/misc/espresso/pair.c \ + src/misc/espresso/part.c \ + src/misc/espresso/primes.c \ + src/misc/espresso/reduce.c \ + src/misc/espresso/rows.c \ + src/misc/espresso/set.c \ + src/misc/espresso/setc.c \ + src/misc/espresso/sharp.c \ + src/misc/espresso/sminterf.c \ + src/misc/espresso/solution.c \ + src/misc/espresso/sparse.c \ + src/misc/espresso/unate.c \ + src/misc/espresso/verify.c diff --git a/src/misc/espresso/opo.c b/src/misc/espresso/opo.c new file mode 100644 index 00000000..8daa0771 --- /dev/null +++ b/src/misc/espresso/opo.c @@ -0,0 +1,624 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +#include "espresso.h" + +/* + * Phase assignment technique (T. Sasao): + * + * 1. create a function with 2*m outputs which implements the + * original function and its complement for each output + * + * 2. minimize this function + * + * 3. choose the minimum number of prime implicants from the + * result of step 2 which are needed to realize either a function + * or its complement for each output + * + * Step 3 is performed in a rather crude way -- by simply multiplying + * out a large expression of the form: + * + * I = (ab + cdef)(acd + bgh) ... + * + * which is a product of m expressions where each expression has two + * product terms -- one representing which primes are needed for the + * function, and one representing which primes are needed for the + * complement. The largest product term resulting shows which primes + * to keep to implement one function or the other for each output. + * For problems with many outputs, this may grind to a + * halt. + * + * Untried: form complement of I and use unate_complement ... + * + * I have unsuccessfully tried several modifications to the basic + * algorithm. The first is quite simple: use Sasao's technique, but + * only commit to a single output at a time (rather than all + * outputs). The goal would be that the later minimizations can "take + * into account" the partial assignment at each step. This is + * expensive (m+1 minimizations rather than 2), and the results are + * discouraging. + * + * The second modification is rather complicated. The result from the + * minimization in step 2 is guaranteed to be minimal. Hence, for + * each output, the set of primes with a 1 in that output are both + * necessary and sufficient to implement the function. Espresso + * achieves the minimality using the routine MAKE_SPARSE. The + * modification is to prevent MAKE_SPARSE from running. Hence, there + * are potentially many subsets of the set of primes with a 1 in a + * column which can be used to implement that output. We use + * IRREDUNDANT to enumerate all possible subsets and then proceed as + * before. + */ + +static int opo_no_make_sparse; +static int opo_repeated; +static int opo_exact; +static void minimize(); + +void phase_assignment(PLA, opo_strategy) +pPLA PLA; +int opo_strategy; +{ + opo_no_make_sparse = opo_strategy % 2; + skip_make_sparse = opo_no_make_sparse; + opo_repeated = (opo_strategy / 2) % 2; + opo_exact = (opo_strategy / 4) % 2; + + /* Determine a phase assignment */ + if (PLA->phase != NULL) { + FREE(PLA->phase); + } + + if (opo_repeated) { + PLA->phase = set_save(cube.fullset); + repeated_phase_assignment(PLA); + } else { + PLA->phase = find_phase(PLA, 0, (pcube) NULL); + } + + /* Now minimize with this assignment */ + skip_make_sparse = FALSE; + (void) set_phase(PLA); + minimize(PLA); +} + +/* + * repeated_phase_assignment -- an alternate strategy which commits + * to a single phase assignment a step at a time. Performs m + 1 + * minimizations ! + */ +void repeated_phase_assignment(PLA) +pPLA PLA; +{ + int i; + pcube phase; + + for(i = 0; i < cube.part_size[cube.output]; i++) { + + /* Find best assignment for all undecided outputs */ + phase = find_phase(PLA, i, PLA->phase); + + /* Commit for only a single output ... */ + if (! is_in_set(phase, cube.first_part[cube.output] + i)) { + set_remove(PLA->phase, cube.first_part[cube.output] + i); + } + + if (trace || summary) { + printf("\nOPO loop for output #%d\n", i); + printf("PLA->phase is %s\n", pc1(PLA->phase)); + printf("phase is %s\n", pc1(phase)); + } + set_free(phase); + } +} + + +/* + * find_phase -- find a phase assignment for the PLA for all outputs starting + * with output number first_output. + */ +pcube find_phase(PLA, first_output, phase1) +pPLA PLA; +int first_output; +pcube phase1; +{ + pcube phase; + pPLA PLA1; + + phase = set_save(cube.fullset); + + /* setup the double-phase characteristic function, resize the cube */ + PLA1 = new_PLA(); + PLA1->F = sf_save(PLA->F); + PLA1->R = sf_save(PLA->R); + PLA1->D = sf_save(PLA->D); + if (phase1 != NULL) { + PLA1->phase = set_save(phase1); + (void) set_phase(PLA1); + } + EXEC_S(output_phase_setup(PLA1, first_output), "OPO-SETUP ", PLA1->F); + + /* minimize the double-phase function */ + minimize(PLA1); + + /* set the proper phases according to what gives a minimum solution */ + EXEC_S(PLA1->F = opo(phase, PLA1->F, PLA1->D, PLA1->R, first_output), + "OPO ", PLA1->F); + free_PLA(PLA1); + + /* set the cube structure to reflect the old size */ + setdown_cube(); + cube.part_size[cube.output] -= + (cube.part_size[cube.output] - first_output) / 2; + cube_setup(); + + return phase; +} + +/* + * opo -- multiply the expression out to determine a minimum subset of + * primes. + */ + +/*ARGSUSED*/ +pcover opo(phase, T, D, R, first_output) +pcube phase; +pcover T, D, R; +int first_output; +{ + int offset, output, i, last_output, ind; + pset pdest, select, p, p1, last, last1, not_covered, tmp; + pset_family temp, T1, T2; + + /* must select all primes for outputs [0 .. first_output-1] */ + select = set_full(T->count); + for(output = 0; output < first_output; output++) { + ind = cube.first_part[cube.output] + output; + foreachi_set(T, i, p) { + if (is_in_set(p, ind)) { + set_remove(select, i); + } + } + } + + /* Recursively perform the intersections */ + offset = (cube.part_size[cube.output] - first_output) / 2; + last_output = first_output + offset - 1; + temp = opo_recur(T, D, select, offset, first_output, last_output); + + /* largest set is on top -- select primes which are inferred from it */ + pdest = temp->data; + T1 = new_cover(T->count); + foreachi_set(T, i, p) { + if (! is_in_set(pdest, i)) { + T1 = sf_addset(T1, p); + } + } + + set_free(select); + sf_free(temp); + + /* finding phases is difficult -- see which functions are not covered */ + T2 = complement(cube1list(T1)); + not_covered = new_cube(); + tmp = new_cube(); + foreach_set(T, last, p) { + foreach_set(T2, last1, p1) { + if (cdist0(p, p1)) { + (void) set_or(not_covered, not_covered, set_and(tmp, p, p1)); + } + } + } + free_cover(T); + free_cover(T2); + set_free(tmp); + + /* Now reflect the phase choice in a single cube */ + for(output = first_output; output <= last_output; output++) { + ind = cube.first_part[cube.output] + output; + if (is_in_set(not_covered, ind)) { + if (is_in_set(not_covered, ind + offset)) { + fatal("error in output phase assignment"); + } else { + set_remove(phase, ind); + } + } + } + set_free(not_covered); + return T1; +} + +pset_family opo_recur(T, D, select, offset, first, last) +pcover T, D; +pcube select; +int offset, first, last; +{ + static int level = 0; + int middle; + pset_family sl, sr, temp; + + level++; + if (first == last) { +#if 0 + if (opo_no_make_sparse) { + temp = form_cover_table(T, D, select, first, first + offset); + } else { + temp = opo_leaf(T, select, first, first + offset); + } +#else + temp = opo_leaf(T, select, first, first + offset); +#endif + } else { + middle = (first + last) / 2; + sl = opo_recur(T, D, select, offset, first, middle); + sr = opo_recur(T, D, select, offset, middle+1, last); + temp = unate_intersect(sl, sr, level == 1); + if (trace) { + printf("# OPO[%d]: %4d = %4d x %4d, time = %s\n", level - 1, + temp->count, sl->count, sr->count, print_time(ptime())); + (void) fflush(stdout); + } + free_cover(sl); + free_cover(sr); + } + level--; + return temp; +} + + +pset_family opo_leaf(T, select, out1, out2) +register pcover T; +pset select; +int out1, out2; +{ + register pset_family temp; + register pset p, pdest; + register int i; + + out1 += cube.first_part[cube.output]; + out2 += cube.first_part[cube.output]; + + /* Allocate space for the result */ + temp = sf_new(2, T->count); + + /* Find which primes are needed for the ON-set of this fct */ + pdest = GETSET(temp, temp->count++); + (void) set_copy(pdest, select); + foreachi_set(T, i, p) { + if (is_in_set(p, out1)) { + set_remove(pdest, i); + } + } + + /* Find which primes are needed for the OFF-set of this fct */ + pdest = GETSET(temp, temp->count++); + (void) set_copy(pdest, select); + foreachi_set(T, i, p) { + if (is_in_set(p, out2)) { + set_remove(pdest, i); + } + } + + return temp; +} + +#if 0 +pset_family form_cover_table(F, D, select, f, fbar) +pcover F, D; +pset select; +int f, fbar; /* indices of f and fbar in the output part */ +{ + register int i; + register pcube p; + pset_family f_table, fbar_table; + + /* setup required for fcube_is_covered */ + Rp_size = F->count; + Rp_start = set_new(Rp_size); + foreachi_set(F, i, p) { + PUTSIZE(p, i); + } + foreachi_set(D, i, p) { + RESET(p, REDUND); + } + + f_table = find_covers(F, D, select, f); + fbar_table = find_covers(F, D, select, fbar); + f_table = sf_append(f_table, fbar_table); + + set_free(Rp_start); + return f_table; +} + + +pset_family find_covers(F, D, select, n) +pcover F, D; +register pset select; +int n; +{ + register pset p, last, new; + pcover F1; + pcube *Flist; + pset_family f_table, table; + int i; + + n += cube.first_part[cube.output]; + + /* save cubes in this output, and remove the output variable */ + F1 = new_cover(F->count); + foreach_set(F, last, p) + if (is_in_set(p, n)) { + new = GETSET(F1, F1->count++); + set_or(new, p, cube.var_mask[cube.output]); + PUTSIZE(new, SIZE(p)); + SET(new, REDUND); + } + + /* Find ways (sop form) to fail to cover output indexed by n */ + Flist = cube2list(F1, D); + table = sf_new(10, Rp_size); + foreach_set(F1, last, p) { + set_fill(Rp_start, Rp_size); + set_remove(Rp_start, SIZE(p)); + table = sf_append(table, fcube_is_covered(Flist, p)); + RESET(p, REDUND); + } + set_fill(Rp_start, Rp_size); + foreach_set(table, last, p) { + set_diff(p, Rp_start, p); + } + + /* complement this to get possible ways to cover the function */ + for(i = 0; i < Rp_size; i++) { + if (! is_in_set(select, i)) { + p = set_new(Rp_size); + set_insert(p, i); + table = sf_addset(table, p); + set_free(p); + } + } + f_table = unate_compl(table); + + /* what a pain, but we need bitwise complement of this */ + set_fill(Rp_start, Rp_size); + foreach_set(f_table, last, p) { + set_diff(p, Rp_start, p); + } + + free_cubelist(Flist); + sf_free(F1); + return f_table; +} +#endif + +/* + * Take a PLA (ON-set, OFF-set and DC-set) and create the + * "double-phase characteristic function" which is merely a new + * function which has twice as many outputs and realizes both the + * function and the complement. + * + * The cube structure is assumed to represent the PLA upon entering. + * It will be modified to represent the double-phase function upon + * exit. + * + * Only the outputs numbered starting with "first_output" are + * duplicated in the output part + */ + +output_phase_setup(PLA, first_output) +INOUT pPLA PLA; +int first_output; +{ + pcover F, R, D; + pcube mask, mask1, last; + int first_part, offset; + bool save; + register pcube p, pr, pf; + register int i, last_part; + + if (cube.output == -1) + fatal("output_phase_setup: must have an output"); + + F = PLA->F; + D = PLA->D; + R = PLA->R; + first_part = cube.first_part[cube.output] + first_output; + last_part = cube.last_part[cube.output]; + offset = cube.part_size[cube.output] - first_output; + + /* Change the output size, setup the cube structure */ + setdown_cube(); + cube.part_size[cube.output] += offset; + cube_setup(); + + /* Create a mask to select that part of the cube which isn't changing */ + mask = set_save(cube.fullset); + for(i = first_part; i < cube.size; i++) + set_remove(mask, i); + mask1 = set_save(mask); + for(i = cube.first_part[cube.output]; i < first_part; i++) { + set_remove(mask1, i); + } + + PLA->F = new_cover(F->count + R->count); + PLA->R = new_cover(F->count + R->count); + PLA->D = new_cover(D->count); + + foreach_set(F, last, p) { + pf = GETSET(PLA->F, (PLA->F)->count++); + pr = GETSET(PLA->R, (PLA->R)->count++); + INLINEset_and(pf, mask, p); + INLINEset_and(pr, mask1, p); + for(i = first_part; i <= last_part; i++) + if (is_in_set(p, i)) + set_insert(pf, i); + save = FALSE; + for(i = first_part; i <= last_part; i++) + if (is_in_set(p, i)) + save = TRUE, set_insert(pr, i+offset); + if (! save) PLA->R->count--; + } + + foreach_set(R, last, p) { + pf = GETSET(PLA->F, (PLA->F)->count++); + pr = GETSET(PLA->R, (PLA->R)->count++); + INLINEset_and(pf, mask1, p); + INLINEset_and(pr, mask, p); + save = FALSE; + for(i = first_part; i <= last_part; i++) + if (is_in_set(p, i)) + save = TRUE, set_insert(pf, i+offset); + if (! save) PLA->F->count--; + for(i = first_part; i <= last_part; i++) + if (is_in_set(p, i)) + set_insert(pr, i); + } + + foreach_set(D, last, p) { + pf = GETSET(PLA->D, (PLA->D)->count++); + INLINEset_and(pf, mask, p); + for(i = first_part; i <= last_part; i++) + if (is_in_set(p, i)) { + set_insert(pf, i); + set_insert(pf, i+offset); + } + } + + free_cover(F); + free_cover(D); + free_cover(R); + set_free(mask); + set_free(mask1); +} + +/* + * set_phase -- given a "cube" which describes which phases of the output + * are to be implemented, compute the appropriate on-set and off-set + */ +pPLA set_phase(PLA) +INOUT pPLA PLA; +{ + pcover F1, R1; + register pcube last, p, outmask; + register pcube temp=cube.temp[0], phase=PLA->phase, phase1=cube.temp[1]; + + outmask = cube.var_mask[cube.num_vars - 1]; + set_diff(phase1, outmask, phase); + set_or(phase1, set_diff(temp, cube.fullset, outmask), phase1); + F1 = new_cover((PLA->F)->count + (PLA->R)->count); + R1 = new_cover((PLA->F)->count + (PLA->R)->count); + + foreach_set(PLA->F, last, p) { + if (! setp_disjoint(set_and(temp, p, phase), outmask)) + set_copy(GETSET(F1, F1->count++), temp); + if (! setp_disjoint(set_and(temp, p, phase1), outmask)) + set_copy(GETSET(R1, R1->count++), temp); + } + foreach_set(PLA->R, last, p) { + if (! setp_disjoint(set_and(temp, p, phase), outmask)) + set_copy(GETSET(R1, R1->count++), temp); + if (! setp_disjoint(set_and(temp, p, phase1), outmask)) + set_copy(GETSET(F1, F1->count++), temp); + } + free_cover(PLA->F); + free_cover(PLA->R); + PLA->F = F1; + PLA->R = R1; + return PLA; +} + +#define POW2(x) (1 << (x)) + +void opoall(PLA, first_output, last_output, opo_strategy) +pPLA PLA; +int first_output, last_output; +int opo_strategy; +{ + pcover F, D, R, best_F, best_D, best_R; + int i, j, ind, num; + pcube bestphase; + + opo_exact = opo_strategy; + + if (PLA->phase != NULL) { + set_free(PLA->phase); + } + + bestphase = set_save(cube.fullset); + best_F = sf_save(PLA->F); + best_D = sf_save(PLA->D); + best_R = sf_save(PLA->R); + + for(i = 0; i < POW2(last_output - first_output + 1); i++) { + + /* save the initial PLA covers */ + F = sf_save(PLA->F); + D = sf_save(PLA->D); + R = sf_save(PLA->R); + + /* compute the phase cube for this iteration */ + PLA->phase = set_save(cube.fullset); + num = i; + for(j = last_output; j >= first_output; j--) { + if (num % 2 == 0) { + ind = cube.first_part[cube.output] + j; + set_remove(PLA->phase, ind); + } + num /= 2; + } + + /* set the phase and minimize */ + (void) set_phase(PLA); + printf("# phase is %s\n", pc1(PLA->phase)); + summary = TRUE; + minimize(PLA); + + /* see if this is the best so far */ + if (PLA->F->count < best_F->count) { + /* save new best solution */ + set_copy(bestphase, PLA->phase); + sf_free(best_F); + sf_free(best_D); + sf_free(best_R); + best_F = PLA->F; + best_D = PLA->D; + best_R = PLA->R; + } else { + /* throw away the solution */ + free_cover(PLA->F); + free_cover(PLA->D); + free_cover(PLA->R); + } + set_free(PLA->phase); + + /* restore the initial PLA covers */ + PLA->F = F; + PLA->D = D; + PLA->R = R; + } + + /* one more minimization to restore the best answer */ + PLA->phase = bestphase; + sf_free(PLA->F); + sf_free(PLA->D); + sf_free(PLA->R); + PLA->F = best_F; + PLA->D = best_D; + PLA->R = best_R; +} + +static void minimize(PLA) +pPLA PLA; +{ + if (opo_exact) { + EXEC_S(PLA->F = minimize_exact(PLA->F,PLA->D,PLA->R,1), "EXACT", PLA->F); + } else { + EXEC_S(PLA->F = espresso(PLA->F, PLA->D, PLA->R), "ESPRESSO ",PLA->F); + } +} diff --git a/src/misc/espresso/pair.c b/src/misc/espresso/pair.c new file mode 100644 index 00000000..a8077176 --- /dev/null +++ b/src/misc/espresso/pair.c @@ -0,0 +1,675 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +#include "espresso.h" + +void set_pair(PLA) +pPLA PLA; +{ + set_pair1(PLA, TRUE); +} + +void set_pair1(PLA, adjust_labels) +pPLA PLA; +bool adjust_labels; +{ + int i, var, *paired, newvar; + int old_num_vars, old_num_binary_vars, old_size, old_mv_start; + int *new_part_size, new_num_vars, new_num_binary_vars, new_mv_start; + ppair pair = PLA->pair; + char scratch[1000], **oldlabel, *var1, *var1bar, *var2, *var2bar; + + if (adjust_labels) + makeup_labels(PLA); + + /* Check the pair structure for valid entries and see which binary + variables are left unpaired + */ + paired = ALLOC(bool, cube.num_binary_vars); + for(var = 0; var < cube.num_binary_vars; var++) + paired[var] = FALSE; + for(i = 0; i < pair->cnt; i++) + if ((pair->var1[i] > 0 && pair->var1[i] <= cube.num_binary_vars) && + (pair->var2[i] > 0 && pair->var2[i] <= cube.num_binary_vars)) { + paired[pair->var1[i]-1] = TRUE; + paired[pair->var2[i]-1] = TRUE; + } else + fatal("can only pair binary-valued variables"); + + PLA->F = delvar(pairvar(PLA->F, pair), paired); + PLA->R = delvar(pairvar(PLA->R, pair), paired); + PLA->D = delvar(pairvar(PLA->D, pair), paired); + + /* Now painfully adjust the cube size */ + old_size = cube.size; + old_num_vars = cube.num_vars; + old_num_binary_vars = cube.num_binary_vars; + old_mv_start = cube.first_part[cube.num_binary_vars]; + /* Create the new cube.part_size vector and setup the cube structure */ + new_num_binary_vars = 0; + for(var = 0; var < old_num_binary_vars; var++) + new_num_binary_vars += (paired[var] == FALSE); + new_num_vars = new_num_binary_vars + pair->cnt; + new_num_vars += old_num_vars - old_num_binary_vars; + new_part_size = ALLOC(int, new_num_vars); + for(var = 0; var < pair->cnt; var++) + new_part_size[new_num_binary_vars + var] = 4; + for(var = 0; var < old_num_vars - old_num_binary_vars; var++) + new_part_size[new_num_binary_vars + pair->cnt + var] = + cube.part_size[old_num_binary_vars + var]; + setdown_cube(); + FREE(cube.part_size); + cube.num_vars = new_num_vars; + cube.num_binary_vars = new_num_binary_vars; + cube.part_size = new_part_size; + cube_setup(); + + /* hack with the labels to get them correct */ + if (adjust_labels) { + oldlabel = PLA->label; + PLA->label = ALLOC(char *, cube.size); + for(var = 0; var < pair->cnt; var++) { + newvar = cube.num_binary_vars*2 + var*4; + var1 = oldlabel[ (pair->var1[var]-1) * 2 + 1]; + var2 = oldlabel[ (pair->var2[var]-1) * 2 + 1]; + var1bar = oldlabel[ (pair->var1[var]-1) * 2]; + var2bar = oldlabel[ (pair->var2[var]-1) * 2]; + (void) sprintf(scratch, "%s+%s", var1bar, var2bar); + PLA->label[newvar] = util_strsav(scratch); + (void) sprintf(scratch, "%s+%s", var1bar, var2); + PLA->label[newvar+1] = util_strsav(scratch); + (void) sprintf(scratch, "%s+%s", var1, var2bar); + PLA->label[newvar+2] = util_strsav(scratch); + (void) sprintf(scratch, "%s+%s", var1, var2); + PLA->label[newvar+3] = util_strsav(scratch); + } + /* Copy the old labels for the unpaired binary vars */ + i = 0; + for(var = 0; var < old_num_binary_vars; var++) { + if (paired[var] == FALSE) { + PLA->label[2*i] = oldlabel[2*var]; + PLA->label[2*i+1] = oldlabel[2*var+1]; + oldlabel[2*var] = oldlabel[2*var+1] = (char *) NULL; + i++; + } + } + /* Copy the old labels for the remaining unpaired vars */ + new_mv_start = cube.num_binary_vars*2 + pair->cnt*4; + for(i = old_mv_start; i < old_size; i++) { + PLA->label[new_mv_start + i - old_mv_start] = oldlabel[i]; + oldlabel[i] = (char *) NULL; + } + /* free remaining entries in oldlabel */ + for(i = 0; i < old_size; i++) + if (oldlabel[i] != (char *) NULL) + FREE(oldlabel[i]); + FREE(oldlabel); + } + + /* the paired variables should not be sparse (cf. mv_reduce/raise_in)*/ + for(var = 0; var < pair->cnt; var++) + cube.sparse[cube.num_binary_vars + var] = 0; + FREE(paired); +} + +pcover pairvar(A, pair) +pcover A; +ppair pair; +{ + register pcube last, p; + register int val, p1, p2, b1, b0; + int insert_col, pairnum; + + insert_col = cube.first_part[cube.num_vars - 1]; + + /* stretch the cover matrix to make room for the paired variables */ + A = sf_delcol(A, insert_col, -4*pair->cnt); + + /* compute the paired values */ + foreach_set(A, last, p) { + for(pairnum = 0; pairnum < pair->cnt; pairnum++) { + p1 = cube.first_part[pair->var1[pairnum] - 1]; + p2 = cube.first_part[pair->var2[pairnum] - 1]; + b1 = is_in_set(p, p2+1); + b0 = is_in_set(p, p2); + val = insert_col + pairnum * 4; + if (/* a0 */ is_in_set(p, p1)) { + if (b0) + set_insert(p, val + 3); + if (b1) + set_insert(p, val + 2); + } + if (/* a1 */ is_in_set(p, p1+1)) { + if (b0) + set_insert(p, val + 1); + if (b1) + set_insert(p, val); + } + } + } + return A; +} + + +/* delvar -- delete variables from A, minimize the number of column shifts */ +pcover delvar(A, paired) +pcover A; +bool paired[]; +{ + bool run; + int first_run, run_length, var, offset = 0; + + run = FALSE; run_length = 0; + for(var = 0; var < cube.num_binary_vars; var++) + if (paired[var]) + if (run) + run_length += cube.part_size[var]; + else { + run = TRUE; + first_run = cube.first_part[var]; + run_length = cube.part_size[var]; + } + else + if (run) { + A = sf_delcol(A, first_run-offset, run_length); + run = FALSE; + offset += run_length; + } + if (run) + A = sf_delcol(A, first_run-offset, run_length); + return A; +} + +/* + find_optimal_pairing -- find which binary variables should be paired + to maximally reduce the number of terms + + This is essentially the technique outlined by T. Sasao in the + Trans. on Comp., Oct 1984. We estimate the cost of pairing each + pair individually using 1 of 4 strategies: (1) algebraic division + of F by the pair (exactly T. Sasao technique); (2) strong division + of F by the paired variables (using REDUCE/EXPAND/ IRREDUNDANT from + espresso); (3) full minimization using espresso; (4) exact + minimization. These are in order of both increasing accuracy and + increasing difficulty (!) + + Once the n squared pairs have been evaluated, T. Sasao proposes a + graph covering of nodes by disjoint edges. For now, I solve this + problem exhaustively (complexity = (n-1)*(n-3)*...*3*1 for n + variables when n is even). Note that solving this problem exactly + is the same as evaluating the cost function for all possible + pairings. + + n pairs + + 1, 2 1 + 3, 4 3 + 5, 6 15 + 7, 8 105 + 9,10 945 + 11,12 10,395 + 13,14 135,135 + 15,16 2,027,025 + 17,18 34,459,425 + 19,20 654,729,075 +*/ +void find_optimal_pairing(PLA, strategy) +pPLA PLA; +int strategy; +{ + int i, j, **cost_array; + + cost_array = find_pairing_cost(PLA, strategy); + + if (summary) { + printf(" "); + for(i = 0; i < cube.num_binary_vars; i++) + printf("%3d ", i+1); + printf("\n"); + for(i = 0; i < cube.num_binary_vars; i++) { + printf("%3d ", i+1); + for(j = 0; j < cube.num_binary_vars; j++) + printf("%3d ", cost_array[i][j]); + printf("\n"); + } + } + + if (cube.num_binary_vars <= 14) { + PLA->pair = pair_best_cost(cost_array); + } else { + (void) greedy_best_cost(cost_array, &(PLA->pair)); + } + printf("# "); + print_pair(PLA->pair); + + for(i = 0; i < cube.num_binary_vars; i++) + FREE(cost_array[i]); + FREE(cost_array); + + set_pair(PLA); + EXEC_S(PLA->F=espresso(PLA->F,PLA->D,PLA->R),"ESPRESSO ",PLA->F); +} + +int **find_pairing_cost(PLA, strategy) +pPLA PLA; +int strategy; +{ + int var1, var2, **cost_array; + int i, j, xnum_binary_vars, xnum_vars, *xpart_size, cost; + pcover T, Fsave, Dsave, Rsave; + pset mask; +/* char *s;*/ + + /* data is returned in the cost array */ + cost_array = ALLOC(int *, cube.num_binary_vars); + for(i = 0; i < cube.num_binary_vars; i++) + cost_array[i] = ALLOC(int, cube.num_binary_vars); + for(i = 0; i < cube.num_binary_vars; i++) + for(j = 0; j < cube.num_binary_vars; j++) + cost_array[i][j] = 0; + + /* Setup the pair structure for pairing variables together */ + PLA->pair = pair_new(1); + PLA->pair->cnt = 1; + + for(var1 = 0; var1 < cube.num_binary_vars-1; var1++) { + for(var2 = var1+1; var2 < cube.num_binary_vars; var2++) { + /* if anything but simple strategy, perform setup */ + if (strategy > 0) { + /* save the original covers */ + Fsave = sf_save(PLA->F); + Dsave = sf_save(PLA->D); + Rsave = sf_save(PLA->R); + + /* save the original cube structure */ + xnum_binary_vars = cube.num_binary_vars; + xnum_vars = cube.num_vars; + xpart_size = ALLOC(int, cube.num_vars); + for(i = 0; i < cube.num_vars; i++) + xpart_size[i] = cube.part_size[i]; + + /* pair two variables together */ + PLA->pair->var1[0] = var1 + 1; + PLA->pair->var2[0] = var2 + 1; + set_pair1(PLA, /* adjust_labels */ FALSE); + } + + + /* decide how to best estimate worth of this pairing */ + switch(strategy) { + case 3: + /*s = "exact minimization";*/ + PLA->F = minimize_exact(PLA->F, PLA->D, PLA->R, 1); + cost = Fsave->count - PLA->F->count; + break; + case 2: + /*s = "full minimization";*/ + PLA->F = espresso(PLA->F, PLA->D, PLA->R); + cost = Fsave->count - PLA->F->count; + break; + case 1: + /*s = "strong division";*/ + PLA->F = reduce(PLA->F, PLA->D); + PLA->F = expand(PLA->F, PLA->R, FALSE); + PLA->F = irredundant(PLA->F, PLA->D); + cost = Fsave->count - PLA->F->count; + break; + case 0: + /*s = "weak division";*/ + mask = new_cube(); + set_or(mask, cube.var_mask[var1], cube.var_mask[var2]); + T = dist_merge(sf_save(PLA->F), mask); + cost = PLA->F->count - T->count; + sf_free(T); + set_free(mask); + } + + cost_array[var1][var2] = cost; + + if (strategy > 0) { + /* restore the original cube structure -- free the new ones */ + setdown_cube(); + FREE(cube.part_size); + cube.num_binary_vars = xnum_binary_vars; + cube.num_vars = xnum_vars; + cube.part_size = xpart_size; + cube_setup(); + + /* restore the original cover(s) -- free the new ones */ + sf_free(PLA->F); + sf_free(PLA->D); + sf_free(PLA->R); + PLA->F = Fsave; + PLA->D = Dsave; + PLA->R = Rsave; + } + } + } + + pair_free(PLA->pair); + PLA->pair = NULL; + return cost_array; +} + +static int best_cost; +static int **cost_array; +static ppair best_pair; +static pset best_phase; +static pPLA global_PLA; +static pcover best_F, best_D, best_R; +static int pair_minim_strategy; + + +print_pair(pair) +ppair pair; +{ + int i; + + printf("pair is"); + for(i = 0; i < pair->cnt; i++) + printf (" (%d %d)", pair->var1[i], pair->var2[i]); + printf("\n"); +} + + +int greedy_best_cost(cost_array_local, pair_p) +int **cost_array_local; +ppair *pair_p; +{ + int i, j, besti, bestj, maxcost, total_cost; + pset cand; + ppair pair; + + pair = pair_new(cube.num_binary_vars); + cand = set_full(cube.num_binary_vars); + total_cost = 0; + + while (set_ord(cand) >= 2) { + maxcost = -1; + for(i = 0; i < cube.num_binary_vars; i++) { + if (is_in_set(cand, i)) { + for(j = i+1; j < cube.num_binary_vars; j++) { + if (is_in_set(cand, j)) { + if (cost_array_local[i][j] > maxcost) { + maxcost = cost_array_local[i][j]; + besti = i; + bestj = j; + } + } + } + } + } + pair->var1[pair->cnt] = besti+1; + pair->var2[pair->cnt] = bestj+1; + pair->cnt++; + set_remove(cand, besti); + set_remove(cand, bestj); + total_cost += maxcost; + } + set_free(cand); + *pair_p = pair; + return total_cost; +} + + +ppair pair_best_cost(cost_array_local) +int **cost_array_local; +{ + ppair pair; + pset candidate; + + best_cost = -1; + best_pair = NULL; + cost_array = cost_array_local; + + pair = pair_new(cube.num_binary_vars); + candidate = set_full(cube.num_binary_vars); + generate_all_pairs(pair, cube.num_binary_vars, candidate, find_best_cost); + pair_free(pair); + set_free(candidate); + return best_pair; +} + + +int find_best_cost(pair) +register ppair pair; +{ + register int i, cost; + + cost = 0; + for(i = 0; i < pair->cnt; i++) + cost += cost_array[pair->var1[i]-1][pair->var2[i]-1]; + if (cost > best_cost) { + best_cost = cost; + best_pair = pair_save(pair, pair->cnt); + } + if ((debug & MINCOV) && trace) { + printf("cost is %d ", cost); + print_pair(pair); + } +} + +/* + pair_all: brute-force approach to try all possible pairings + + pair_strategy is: + 2) for espresso + 3) for minimize_exact + 4) for phase assignment +*/ + +pair_all(PLA, pair_strategy) +pPLA PLA; +int pair_strategy; +{ + ppair pair; + pset candidate; + + global_PLA = PLA; + pair_minim_strategy = pair_strategy; + best_cost = PLA->F->count + 1; + best_pair = NULL; + best_phase = NULL; + best_F = best_D = best_R = NULL; + pair = pair_new(cube.num_binary_vars); + candidate = set_fill(set_new(cube.num_binary_vars), cube.num_binary_vars); + + generate_all_pairs(pair, cube.num_binary_vars, candidate, minimize_pair); + + pair_free(pair); + set_free(candidate); + + PLA->pair = best_pair; + PLA->phase = best_phase; +/* not really necessary + if (phase != NULL) + (void) set_phase(PLA->phase); +*/ + set_pair(PLA); + printf("# "); + print_pair(PLA->pair); + + sf_free(PLA->F); + sf_free(PLA->D); + sf_free(PLA->R); + PLA->F = best_F; + PLA->D = best_D; + PLA->R = best_R; +} + + +/* + * minimize_pair -- called as each pair is generated + */ +int minimize_pair(pair) +ppair pair; +{ + pcover Fsave, Dsave, Rsave; + int i, xnum_binary_vars, xnum_vars, *xpart_size; + + /* save the original covers */ + Fsave = sf_save(global_PLA->F); + Dsave = sf_save(global_PLA->D); + Rsave = sf_save(global_PLA->R); + + /* save the original cube structure */ + xnum_binary_vars = cube.num_binary_vars; + xnum_vars = cube.num_vars; + xpart_size = ALLOC(int, cube.num_vars); + for(i = 0; i < cube.num_vars; i++) + xpart_size[i] = cube.part_size[i]; + + /* setup the paired variables */ + global_PLA->pair = pair; + set_pair1(global_PLA, /* adjust_labels */ FALSE); + + /* call the minimizer */ + if (summary) + print_pair(pair); + switch(pair_minim_strategy) { + case 2: + EXEC_S(phase_assignment(global_PLA,0), "OPO ", global_PLA->F); + if (summary) + printf("# phase is %s\n", pc1(global_PLA->phase)); + break; + case 1: + EXEC_S(global_PLA->F = minimize_exact(global_PLA->F, global_PLA->D, + global_PLA->R, 1), "EXACT ", global_PLA->F); + break; + case 0: + EXEC_S(global_PLA->F = espresso(global_PLA->F, global_PLA->D, + global_PLA->R), "ESPRESSO ", global_PLA->F); + break; + default: + break; + } + + /* see if we have a new best solution */ + if (global_PLA->F->count < best_cost) { + best_cost = global_PLA->F->count; + best_pair = pair_save(pair, pair->cnt); + best_phase = global_PLA->phase!=NULL?set_save(global_PLA->phase):NULL; + if (best_F != NULL) sf_free(best_F); + if (best_D != NULL) sf_free(best_D); + if (best_R != NULL) sf_free(best_R); + best_F = sf_save(global_PLA->F); + best_D = sf_save(global_PLA->D); + best_R = sf_save(global_PLA->R); + } + + /* restore the original cube structure -- free the new ones */ + setdown_cube(); + FREE(cube.part_size); + cube.num_binary_vars = xnum_binary_vars; + cube.num_vars = xnum_vars; + cube.part_size = xpart_size; + cube_setup(); + + /* restore the original cover(s) -- free the new ones */ + sf_free(global_PLA->F); + sf_free(global_PLA->D); + sf_free(global_PLA->R); + global_PLA->F = Fsave; + global_PLA->D = Dsave; + global_PLA->R = Rsave; + global_PLA->pair = NULL; + global_PLA->phase = NULL; +} + +generate_all_pairs(pair, n, candidate, action) +ppair pair; +int n; +pset candidate; +int (*action)(); +{ + int i, j; + pset recur_candidate; + ppair recur_pair; + + if (set_ord(candidate) < 2) { + (*action)(pair); + return; + } + + recur_pair = pair_save(pair, n); + recur_candidate = set_save(candidate); + + /* Find first variable still in the candidate set */ + for(i = 0; i < n; i++) + if (is_in_set(candidate, i)) + break; + + /* Try all pairs of i with other variables */ + for(j = i+1; j < n; j++) + if (is_in_set(candidate, j)) { + /* pair (i j) -- remove from candidate set for future pairings */ + set_remove(recur_candidate, i); + set_remove(recur_candidate, j); + + /* add to the pair array */ + recur_pair->var1[recur_pair->cnt] = i+1; + recur_pair->var2[recur_pair->cnt] = j+1; + recur_pair->cnt++; + + /* recur looking for the end ... */ + generate_all_pairs(recur_pair, n, recur_candidate, action); + + /* now break this pair, and restore candidate set */ + recur_pair->cnt--; + set_insert(recur_candidate, i); + set_insert(recur_candidate, j); + } + + /* if odd, generate all pairs which do NOT include i */ + if ((set_ord(candidate) % 2) == 1) { + set_remove(recur_candidate, i); + generate_all_pairs(recur_pair, n, recur_candidate, action); + } + + pair_free(recur_pair); + set_free(recur_candidate); +} + +ppair pair_new(n) +register int n; +{ + register ppair pair1; + + pair1 = ALLOC(pair_t, 1); + pair1->cnt = 0; + pair1->var1 = ALLOC(int, n); + pair1->var2 = ALLOC(int, n); + return pair1; +} + + +ppair pair_save(pair, n) +register ppair pair; +register int n; +{ + register int k; + register ppair pair1; + + pair1 = pair_new(n); + pair1->cnt = pair->cnt; + for(k = 0; k < pair->cnt; k++) { + pair1->var1[k] = pair->var1[k]; + pair1->var2[k] = pair->var2[k]; + } + return pair1; +} + + +int pair_free(pair) +register ppair pair; +{ + FREE(pair->var1); + FREE(pair->var2); + FREE(pair); +} diff --git a/src/misc/espresso/part.c b/src/misc/espresso/part.c new file mode 100644 index 00000000..42843aeb --- /dev/null +++ b/src/misc/espresso/part.c @@ -0,0 +1,122 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +#include "mincov_int.h" + +static int visit_col(); + +static void +copy_row(A, prow) +register sm_matrix *A; +register sm_row *prow; +{ + register sm_element *p; + + for(p = prow->first_col; p != 0; p = p->next_col) { + (void) sm_insert(A, p->row_num, p->col_num); + } +} + + +static int +visit_row(A, prow, rows_visited, cols_visited) +sm_matrix *A; +sm_row *prow; +int *rows_visited; +int *cols_visited; +{ + sm_element *p; + sm_col *pcol; + + if (! prow->flag) { + prow->flag = 1; + (*rows_visited)++; + if (*rows_visited == A->nrows) { + return 1; + } + for(p = prow->first_col; p != 0; p = p->next_col) { + pcol = sm_get_col(A, p->col_num); + if (! pcol->flag) { + if (visit_col(A, pcol, rows_visited, cols_visited)) { + return 1; + } + } + } + } + return 0; +} + + +static int +visit_col(A, pcol, rows_visited, cols_visited) +sm_matrix *A; +sm_col *pcol; +int *rows_visited; +int *cols_visited; +{ + sm_element *p; + sm_row *prow; + + if (! pcol->flag) { + pcol->flag = 1; + (*cols_visited)++; + if (*cols_visited == A->ncols) { + return 1; + } + for(p = pcol->first_row; p != 0; p = p->next_row) { + prow = sm_get_row(A, p->row_num); + if (! prow->flag) { + if (visit_row(A, prow, rows_visited, cols_visited)) { + return 1; + } + } + } + } + return 0; +} + +int +sm_block_partition(A, L, R) +sm_matrix *A; +sm_matrix **L, **R; +{ + int cols_visited, rows_visited; + register sm_row *prow; + register sm_col *pcol; + + /* Avoid the trivial case */ + if (A->nrows == 0) { + return 0; + } + + /* Reset the visited flags for each row and column */ + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + prow->flag = 0; + } + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) { + pcol->flag = 0; + } + + cols_visited = rows_visited = 0; + if (visit_row(A, A->first_row, &rows_visited, &cols_visited)) { + /* we found all of the rows */ + return 0; + } else { + *L = sm_alloc(); + *R = sm_alloc(); + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + if (prow->flag) { + copy_row(*L, prow); + } else { + copy_row(*R, prow); + } + } + return 1; + } +} diff --git a/src/misc/espresso/primes.c b/src/misc/espresso/primes.c new file mode 100644 index 00000000..3e40da27 --- /dev/null +++ b/src/misc/espresso/primes.c @@ -0,0 +1,170 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +#include "espresso.h" + +static bool primes_consensus_special_cases(); +static pcover primes_consensus_merge(); +static pcover and_with_cofactor(); + + +/* primes_consensus -- generate primes using consensus */ +pcover primes_consensus(T) +pcube *T; /* T will be disposed of */ +{ + register pcube cl, cr; + register int best; + pcover Tnew, Tl, Tr; + + if (primes_consensus_special_cases(T, &Tnew) == MAYBE) { + cl = new_cube(); + cr = new_cube(); + best = binate_split_select(T, cl, cr, COMPL); + + Tl = primes_consensus(scofactor(T, cl, best)); + Tr = primes_consensus(scofactor(T, cr, best)); + Tnew = primes_consensus_merge(Tl, Tr, cl, cr); + + free_cube(cl); + free_cube(cr); + free_cubelist(T); + } + + return Tnew; +} + +static bool +primes_consensus_special_cases(T, Tnew) +pcube *T; /* will be disposed if answer is determined */ +pcover *Tnew; /* returned only if answer determined */ +{ + register pcube *T1, p, ceil, cof=T[0]; + pcube last; + pcover A; + + /* Check for no cubes in the cover */ + if (T[2] == NULL) { + *Tnew = new_cover(0); + free_cubelist(T); + return TRUE; + } + + /* Check for only a single cube in the cover */ + if (T[3] == NULL) { + *Tnew = sf_addset(new_cover(1), set_or(cof, cof, T[2])); + free_cubelist(T); + return TRUE; + } + + /* Check for a row of all 1's (implies function is a tautology) */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (full_row(p, cof)) { + *Tnew = sf_addset(new_cover(1), cube.fullset); + free_cubelist(T); + return TRUE; + } + } + + /* Check for a column of all 0's which can be factored out */ + ceil = set_save(cof); + for(T1 = T+2; (p = *T1++) != NULL; ) { + INLINEset_or(ceil, ceil, p); + } + if (! setp_equal(ceil, cube.fullset)) { + p = new_cube(); + (void) set_diff(p, cube.fullset, ceil); + (void) set_or(cof, cof, p); + free_cube(p); + + A = primes_consensus(T); + foreach_set(A, last, p) { + INLINEset_and(p, p, ceil); + } + *Tnew = A; + set_free(ceil); + return TRUE; + } + set_free(ceil); + + /* Collect column counts, determine unate variables, etc. */ + massive_count(T); + + /* If single active variable not factored out above, then tautology ! */ + if (cdata.vars_active == 1) { + *Tnew = sf_addset(new_cover(1), cube.fullset); + free_cubelist(T); + return TRUE; + + /* Check for unate cover */ + } else if (cdata.vars_unate == cdata.vars_active) { + A = cubeunlist(T); + *Tnew = sf_contain(A); + free_cubelist(T); + return TRUE; + + /* Not much we can do about it */ + } else { + return MAYBE; + } +} + +static pcover +primes_consensus_merge(Tl, Tr, cl, cr) +pcover Tl, Tr; +pcube cl, cr; +{ + register pcube pl, pr, lastl, lastr, pt; + pcover T, Tsave; + + Tl = and_with_cofactor(Tl, cl); + Tr = and_with_cofactor(Tr, cr); + + T = sf_new(500, Tl->sf_size); + pt = T->data; + Tsave = sf_contain(sf_join(Tl, Tr)); + + foreach_set(Tl, lastl, pl) { + foreach_set(Tr, lastr, pr) { + if (cdist01(pl, pr) == 1) { + consensus(pt, pl, pr); + if (++T->count >= T->capacity) { + Tsave = sf_union(Tsave, sf_contain(T)); + T = sf_new(500, Tl->sf_size); + pt = T->data; + } else { + pt += T->wsize; + } + } + } + } + free_cover(Tl); + free_cover(Tr); + + Tsave = sf_union(Tsave, sf_contain(T)); + return Tsave; +} + + +static pcover +and_with_cofactor(A, cof) +pset_family A; +register pset cof; +{ + register pset last, p; + + foreach_set(A, last, p) { + INLINEset_and(p, p, cof); + if (cdist(p, cube.fullset) > 0) { + RESET(p, ACTIVE); + } else { + SET(p, ACTIVE); + } + } + return sf_inactive(A); +} diff --git a/src/misc/espresso/reduce.c b/src/misc/espresso/reduce.c new file mode 100644 index 00000000..00e4507f --- /dev/null +++ b/src/misc/espresso/reduce.c @@ -0,0 +1,258 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +/* + module: reduce.c + purpose: Perform the Espresso-II reduction step + + Reduction is a technique used to explore larger regions of the + optimization space. We replace each cube of F with a smaller + cube while still maintaining a cover of the same logic function. +*/ + +#include "espresso.h" + +static bool toggle = TRUE; + + +/* + reduce -- replace each cube in F with its reduction + + The reduction of a cube is the smallest cube contained in the cube + which can replace the cube in the original cover without changing + the cover. This is equivalent to the super cube of all of the + essential points in the cube. This can be computed directly. + + The problem is that the order in which the cubes are reduced can + greatly affect the final result. We alternate between two ordering + strategies: + + (1) Order the cubes in ascending order of distance from the + largest cube breaking ties by ordering cubes of equal distance + in descending order of size (sort_reduce) + + (2) Order the cubes in descending order of the inner-product of + the cube and the column sums (mini_sort) + + The real workhorse of this section is the routine SCCC which is + used to find the Smallest Cube Containing the Complement of a cover. + Reduction as proposed by Espresso-II takes a cube and computes its + maximal reduction as the intersection between the cube and the + smallest cube containing the complement of (F u D - {c}) cofactored + against c. + + As usual, the unate-recursive paradigm is used to compute SCCC. + The SCCC of a unate cover is trivial to compute, and thus we perform + Shannon Cofactor expansion attempting to drive the cover to be unate + as fast as possible. +*/ + +pcover reduce(F, D) +INOUT pcover F; +IN pcover D; +{ + register pcube last, p, cunder, *FD; + + /* Order the cubes */ + if (use_random_order) + F = random_order(F); + else { + F = toggle ? sort_reduce(F) : mini_sort(F, descend); + toggle = ! toggle; + } + + /* Try to reduce each cube */ + FD = cube2list(F, D); + foreach_set(F, last, p) { + cunder = reduce_cube(FD, p); /* reduce the cube */ + if (setp_equal(cunder, p)) { /* see if it actually did */ + SET(p, ACTIVE); /* cube remains active */ + SET(p, PRIME); /* cube remains prime ? */ + } else { + if (debug & REDUCE) { + printf("REDUCE: %s to %s %s\n", + pc1(p), pc2(cunder), print_time(ptime())); + } + set_copy(p, cunder); /* save reduced version */ + RESET(p, PRIME); /* cube is no longer prime */ + if (setp_empty(cunder)) + RESET(p, ACTIVE); /* if null, kill the cube */ + else + SET(p, ACTIVE); /* cube is active */ + } + free_cube(cunder); + } + free_cubelist(FD); + + /* Delete any cubes of F which reduced to the empty cube */ + return sf_inactive(F); +} + +/* reduce_cube -- find the maximal reduction of a cube */ +pcube reduce_cube(FD, p) +IN pcube *FD, p; +{ + pcube cunder; + + cunder = sccc(cofactor(FD, p)); + return set_and(cunder, cunder, p); +} + + +/* sccc -- find Smallest Cube Containing the Complement of a cover */ +pcube sccc(T) +INOUT pcube *T; /* T will be disposed of */ +{ + pcube r; + register pcube cl, cr; + register int best; + static int sccc_level = 0; + + if (debug & REDUCE1) { + debug_print(T, "SCCC", sccc_level++); + } + + if (sccc_special_cases(T, &r) == MAYBE) { + cl = new_cube(); + cr = new_cube(); + best = binate_split_select(T, cl, cr, REDUCE1); + r = sccc_merge(sccc(scofactor(T, cl, best)), + sccc(scofactor(T, cr, best)), cl, cr); + free_cubelist(T); + } + + if (debug & REDUCE1) + printf("SCCC[%d]: result is %s\n", --sccc_level, pc1(r)); + return r; +} + + +pcube sccc_merge(left, right, cl, cr) +INOUT register pcube left, right; /* will be disposed of ... */ +INOUT register pcube cl, cr; /* will be disposed of ... */ +{ + INLINEset_and(left, left, cl); + INLINEset_and(right, right, cr); + INLINEset_or(left, left, right); + free_cube(right); + free_cube(cl); + free_cube(cr); + return left; +} + + +/* + sccc_cube -- find the smallest cube containing the complement of a cube + + By DeMorgan's law and the fact that the smallest cube containing a + cover is the "or" of the positional cubes, it is simple to see that + the SCCC is the universe if the cube has more than two active + variables. If there is only a single active variable, then the + SCCC is merely the bitwise complement of the cube in that + variable. A last special case is no active variables, in which + case the SCCC is empty. + + This is "anded" with the incoming cube result. +*/ +pcube sccc_cube(result, p) +register pcube result, p; +{ + register pcube temp=cube.temp[0], mask; + int var; + + if ((var = cactive(p)) >= 0) { + mask = cube.var_mask[var]; + INLINEset_xor(temp, p, mask); + INLINEset_and(result, result, temp); + } + return result; +} + +/* + * sccc_special_cases -- check the special cases for sccc + */ + +bool sccc_special_cases(T, result) +INOUT pcube *T; /* will be disposed if answer is determined */ +OUT pcube *result; /* returned only if answer determined */ +{ + register pcube *T1, p, temp = cube.temp[1], ceil, cof = T[0]; + pcube *A, *B; + + /* empty cover => complement is universe => SCCC is universe */ + if (T[2] == NULL) { + *result = set_save(cube.fullset); + free_cubelist(T); + return TRUE; + } + + /* row of 1's => complement is empty => SCCC is empty */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (full_row(p, cof)) { + *result = new_cube(); + free_cubelist(T); + return TRUE; + } + } + + /* Collect column counts, determine unate variables, etc. */ + massive_count(T); + + /* If cover is unate (or single cube), apply simple rules to find SCCCU */ + if (cdata.vars_unate == cdata.vars_active || T[3] == NULL) { + *result = set_save(cube.fullset); + for(T1 = T+2; (p = *T1++) != NULL; ) { + (void) sccc_cube(*result, set_or(temp, p, cof)); + } + free_cubelist(T); + return TRUE; + } + + /* Check for column of 0's (which can be easily factored( */ + ceil = set_save(cof); + for(T1 = T+2; (p = *T1++) != NULL; ) { + INLINEset_or(ceil, ceil, p); + } + if (! setp_equal(ceil, cube.fullset)) { + *result = sccc_cube(set_save(cube.fullset), ceil); + if (setp_equal(*result, cube.fullset)) { + free_cube(ceil); + } else { + *result = sccc_merge(sccc(cofactor(T,ceil)), + set_save(cube.fullset), ceil, *result); + } + free_cubelist(T); + return TRUE; + } + free_cube(ceil); + + /* Single active column at this point => tautology => SCCC is empty */ + if (cdata.vars_active == 1) { + *result = new_cube(); + free_cubelist(T); + return TRUE; + } + + /* Check for components */ + if (cdata.var_zeros[cdata.best] < CUBELISTSIZE(T)/2) { + if (cubelist_partition(T, &A, &B, debug & REDUCE1) == 0) { + return MAYBE; + } else { + free_cubelist(T); + *result = sccc(A); + ceil = sccc(B); + (void) set_and(*result, *result, ceil); + set_free(ceil); + return TRUE; + } + } + + /* Not much we can do about it */ + return MAYBE; +} diff --git a/src/misc/espresso/rows.c b/src/misc/espresso/rows.c new file mode 100644 index 00000000..bf0c0baa --- /dev/null +++ b/src/misc/espresso/rows.c @@ -0,0 +1,314 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +//#include "port.h" +#include "sparse_int.h" + + +/* + * allocate a new row vector + */ +sm_row * +sm_row_alloc() +{ + register sm_row *prow; + +#ifdef FAST_AND_LOOSE + if (sm_row_freelist == NIL(sm_row)) { + prow = ALLOC(sm_row, 1); + } else { + prow = sm_row_freelist; + sm_row_freelist = prow->next_row; + } +#else + prow = ALLOC(sm_row, 1); +#endif + + prow->row_num = 0; + prow->length = 0; + prow->first_col = prow->last_col = NIL(sm_element); + prow->next_row = prow->prev_row = NIL(sm_row); + prow->flag = 0; + prow->user_word = NIL(char); /* for our user ... */ + return prow; +} + + +/* + * free a row vector -- for FAST_AND_LOOSE, this is real cheap for rows; + * however, freeing a column must still walk down the column discarding + * the elements one-by-one; that is the only use for the extra '-DCOLS' + * compile flag ... + */ +void +sm_row_free(prow) +register sm_row *prow; +{ +#if defined(FAST_AND_LOOSE) && ! defined(COLS) + if (prow->first_col != NIL(sm_element)) { + /* Add the linked list of row items to the free list */ + prow->last_col->next_col = sm_element_freelist; + sm_element_freelist = prow->first_col; + } + + /* Add the row to the free list of rows */ + prow->next_row = sm_row_freelist; + sm_row_freelist = prow; +#else + register sm_element *p, *pnext; + + for(p = prow->first_col; p != 0; p = pnext) { + pnext = p->next_col; + sm_element_free(p); + } + FREE(prow); +#endif +} + + +/* + * duplicate an existing row + */ +sm_row * +sm_row_dup(prow) +register sm_row *prow; +{ + register sm_row *pnew; + register sm_element *p; + + pnew = sm_row_alloc(); + for(p = prow->first_col; p != 0; p = p->next_col) { + (void) sm_row_insert(pnew, p->col_num); + } + return pnew; +} + + +/* + * insert an element into a row vector + */ +sm_element * +sm_row_insert(prow, col) +register sm_row *prow; +register int col; +{ + register sm_element *test, *element; + + /* get a new item, save its address */ + sm_element_alloc(element); + test = element; + sorted_insert(sm_element, prow->first_col, prow->last_col, prow->length, + next_col, prev_col, col_num, col, test); + + /* if item was not used, free it */ + if (element != test) { + sm_element_free(element); + } + + /* either way, return the current new value */ + return test; +} + + +/* + * remove an element from a row vector + */ +void +sm_row_remove(prow, col) +register sm_row *prow; +register int col; +{ + register sm_element *p; + + for(p = prow->first_col; p != 0 && p->col_num < col; p = p->next_col) + ; + if (p != 0 && p->col_num == col) { + dll_unlink(p, prow->first_col, prow->last_col, + next_col, prev_col, prow->length); + sm_element_free(p); + } +} + + +/* + * find an element (if it is in the row vector) + */ +sm_element * +sm_row_find(prow, col) +sm_row *prow; +int col; +{ + register sm_element *p; + + for(p = prow->first_col; p != 0 && p->col_num < col; p = p->next_col) + ; + if (p != 0 && p->col_num == col) { + return p; + } else { + return NIL(sm_element); + } +} + +/* + * return 1 if row p2 contains row p1; 0 otherwise + */ +int +sm_row_contains(p1, p2) +sm_row *p1, *p2; +{ + register sm_element *q1, *q2; + + q1 = p1->first_col; + q2 = p2->first_col; + while (q1 != 0) { + if (q2 == 0 || q1->col_num < q2->col_num) { + return 0; + } else if (q1->col_num == q2->col_num) { + q1 = q1->next_col; + q2 = q2->next_col; + } else { + q2 = q2->next_col; + } + } + return 1; +} + + +/* + * return 1 if row p1 and row p2 share an element in common + */ +int +sm_row_intersects(p1, p2) +sm_row *p1, *p2; +{ + register sm_element *q1, *q2; + + q1 = p1->first_col; + q2 = p2->first_col; + if (q1 == 0 || q2 == 0) return 0; + for(;;) { + if (q1->col_num < q2->col_num) { + if ((q1 = q1->next_col) == 0) { + return 0; + } + } else if (q1->col_num > q2->col_num) { + if ((q2 = q2->next_col) == 0) { + return 0; + } + } else { + return 1; + } + } +} + + +/* + * compare two rows, lexical ordering + */ +int +sm_row_compare(p1, p2) +sm_row *p1, *p2; +{ + register sm_element *q1, *q2; + + q1 = p1->first_col; + q2 = p2->first_col; + while(q1 != 0 && q2 != 0) { + if (q1->col_num != q2->col_num) { + return q1->col_num - q2->col_num; + } + q1 = q1->next_col; + q2 = q2->next_col; + } + + if (q1 != 0) { + return 1; + } else if (q2 != 0) { + return -1; + } else { + return 0; + } +} + + +/* + * return the intersection + */ +sm_row * +sm_row_and(p1, p2) +sm_row *p1, *p2; +{ + register sm_element *q1, *q2; + register sm_row *result; + + result = sm_row_alloc(); + q1 = p1->first_col; + q2 = p2->first_col; + if (q1 == 0 || q2 == 0) return result; + for(;;) { + if (q1->col_num < q2->col_num) { + if ((q1 = q1->next_col) == 0) { + return result; + } + } else if (q1->col_num > q2->col_num) { + if ((q2 = q2->next_col) == 0) { + return result; + } + } else { + (void) sm_row_insert(result, q1->col_num); + if ((q1 = q1->next_col) == 0) { + return result; + } + if ((q2 = q2->next_col) == 0) { + return result; + } + } + } +} + +int +sm_row_hash(prow, modulus) +sm_row *prow; +int modulus; +{ + register int sum; + register sm_element *p; + + sum = 0; + for(p = prow->first_col; p != 0; p = p->next_col) { + sum = (sum*17 + p->col_num) % modulus; + } + return sum; +} + +/* + * remove an element from a row vector (given a pointer to the element) + */ +void +sm_row_remove_element(prow, p) +register sm_row *prow; +register sm_element *p; +{ + dll_unlink(p, prow->first_col, prow->last_col, + next_col, prev_col, prow->length); + sm_element_free(p); +} + + +void +sm_row_print(fp, prow) +FILE *fp; +sm_row *prow; +{ + sm_element *p; + + for(p = prow->first_col; p != 0; p = p->next_col) { + (void) fprintf(fp, " %d", p->col_num); + } +} diff --git a/src/misc/espresso/set.c b/src/misc/espresso/set.c new file mode 100644 index 00000000..fce88288 --- /dev/null +++ b/src/misc/espresso/set.c @@ -0,0 +1,820 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +/* + * set.c -- routines for maniuplating sets and set families + */ + +/* LINTLIBRARY */ + +#include "espresso.h" +static pset_family set_family_garbage = NULL; + +static int intcpy(d, s, n) +register unsigned int *d, *s; +register long n; +{ + register int i; + for(i = 0; i < n; i++) { + *d++ = *s++; + } +} + + +/* bit_index -- find first bit (from LSB) in a word (MSB=bit n, LSB=bit 0) */ +int bit_index(a) +register unsigned int a; +{ + register int i; + if (a == 0) + return -1; + for(i = 0; (a & 1) == 0; a >>= 1, i++) + ; + return i; +} + + +/* set_ord -- count number of elements in a set */ +int set_ord(a) +register pset a; +{ + register int i, sum = 0; + register unsigned int val; + for(i = LOOP(a); i > 0; i--) + if ((val = a[i]) != 0) + sum += count_ones(val); + return sum; +} + +/* set_dist -- distance between two sets (# elements in common) */ +int set_dist(a, b) +register pset a, b; +{ + register int i, sum = 0; + register unsigned int val; + for(i = LOOP(a); i > 0; i--) + if ((val = a[i] & b[i]) != 0) + sum += count_ones(val); + return sum; +} + +/* set_clear -- make "r" the empty set of "size" elements */ +pset set_clear(r, size) +register pset r; +int size; +{ + register int i = LOOPINIT(size); + *r = i; do r[i] = 0; while (--i > 0); + return r; +} + +/* set_fill -- make "r" the universal set of "size" elements */ +pset set_fill(r, size) +register pset r; +register int size; +{ + register int i = LOOPINIT(size); + *r = i; + r[i] = ~ (unsigned) 0; + r[i] >>= i * BPI - size; + while (--i > 0) + r[i] = ~ (unsigned) 0; + return r; +} + +/* set_copy -- copy set a into set r */ +pset set_copy(r, a) +register pset r, a; +{ + register int i = LOOPCOPY(a); + do r[i] = a[i]; while (--i >= 0); + return r; +} + +/* set_and -- compute intersection of sets "a" and "b" */ +pset set_and(r, a, b) +register pset r, a, b; +{ + register int i = LOOP(a); + PUTLOOP(r,i); do r[i] = a[i] & b[i]; while (--i > 0); + return r; +} + +/* set_or -- compute union of sets "a" and "b" */ +pset set_or(r, a, b) +register pset r, a, b; +{ + register int i = LOOP(a); + PUTLOOP(r,i); do r[i] = a[i] | b[i]; while (--i > 0); + return r; +} + +/* set_diff -- compute difference of sets "a" and "b" */ +pset set_diff(r, a, b) +register pset r, a, b; +{ + register int i = LOOP(a); + PUTLOOP(r,i); do r[i] = a[i] & ~b[i]; while (--i > 0); + return r; +} + +/* set_xor -- compute exclusive-or of sets "a" and "b" */ +pset set_xor(r, a, b) +register pset r, a, b; +{ + register int i = LOOP(a); +#ifdef IBM_WATC + PUTLOOP(r,i); do r[i] = (a[i]&~b[i]) | (~a[i]&b[i]); while (--i > 0); +#else + PUTLOOP(r,i); do r[i] = a[i] ^ b[i]; while (--i > 0); +#endif + return r; +} + +/* set_merge -- compute "a" & "mask" | "b" & ~ "mask" */ +pset set_merge(r, a, b, mask) +register pset r, a, b, mask; +{ + register int i = LOOP(a); + PUTLOOP(r,i); do r[i] = (a[i]&mask[i]) | (b[i]&~mask[i]); while (--i > 0); + return r; +} + +/* set_andp -- compute intersection of sets "a" and "b" , TRUE if nonempty */ +bool set_andp(r, a, b) +register pset r, a, b; +{ + register int i = LOOP(a); + register unsigned int x = 0; + PUTLOOP(r,i); do {r[i] = a[i] & b[i]; x |= r[i];} while (--i > 0); + return x != 0; +} + +/* set_orp -- compute union of sets "a" and "b" , TRUE if nonempty */ +bool set_orp(r, a, b) +register pset r, a, b; +{ + register int i = LOOP(a); + register unsigned int x = 0; + PUTLOOP(r,i); do {r[i] = a[i] | b[i]; x |= r[i];} while (--i > 0); + return x != 0; +} + +/* setp_empty -- check if the set "a" is empty */ +bool setp_empty(a) +register pset a; +{ + register int i = LOOP(a); + do if (a[i]) return FALSE; while (--i > 0); + return TRUE; +} + +/* setp_full -- check if the set "a" is the full set of "size" elements */ +bool setp_full(a, size) +register pset a; +register int size; +{ + register int i = LOOP(a); + register unsigned int test; + test = ~ (unsigned) 0; + test >>= i * BPI - size; + if (a[i] != test) + return FALSE; + while (--i > 0) + if (a[i] != (~(unsigned) 0)) + return FALSE; + return TRUE; +} + +/* setp_equal -- check if the set "a" equals set "b" */ +bool setp_equal(a, b) +register pset a, b; +{ + register int i = LOOP(a); + do if (a[i] != b[i]) return FALSE; while (--i > 0); + return TRUE; +} + +/* setp_disjoint -- check if intersection of "a" and "b" is empty */ +bool setp_disjoint(a, b) +register pset a, b; +{ + register int i = LOOP(a); + do if (a[i] & b[i]) return FALSE; while (--i > 0); + return TRUE; +} + +/* setp_implies -- check if "a" implies "b" ("b" contains "a") */ +bool setp_implies(a, b) +register pset a, b; +{ + register int i = LOOP(a); + do if (a[i] & ~b[i]) return FALSE; while (--i > 0); + return TRUE; +} + +/* sf_or -- form the "or" of all sets in a set family */ +pset sf_or(A) +pset_family A; +{ + register pset or, last, p; + + or = set_new(A->sf_size); + foreach_set(A, last, p) + INLINEset_or(or, or, p); + return or; +} + +/* sf_and -- form the "and" of all sets in a set family */ +pset sf_and(A) +pset_family A; +{ + register pset and, last, p; + + and = set_fill(set_new(A->sf_size), A->sf_size); + foreach_set(A, last, p) + INLINEset_and(and, and, p); + return and; +} + +/* sf_active -- make all members of the set family active */ +pset_family sf_active(A) +pset_family A; +{ + register pset p, last; + foreach_set(A, last, p) { + SET(p, ACTIVE); + } + A->active_count = A->count; + return A; +} + + +/* sf_inactive -- remove all inactive cubes in a set family */ +pset_family sf_inactive(A) +pset_family A; +{ + register pset p, last, pdest; + + pdest = A->data; + foreach_set(A, last, p) { + if (TESTP(p, ACTIVE)) { + if (pdest != p) { + INLINEset_copy(pdest, p); + } + pdest += A->wsize; + } else { + A->count--; + } + } + return A; +} + + +/* sf_copy -- copy a set family */ +pset_family sf_copy(R, A) +pset_family R, A; +{ + R->sf_size = A->sf_size; + R->wsize = A->wsize; +/*R->capacity = A->count;*/ +/*R->data = REALLOC(unsigned int, R->data, (long) R->capacity * R->wsize);*/ + R->count = A->count; + R->active_count = A->active_count; + intcpy(R->data, A->data, (long) A->wsize * A->count); + return R; +} + + +/* sf_join -- join A and B into a single set_family */ +pset_family sf_join(A, B) +pset_family A, B; +{ + pset_family R; + long asize = A->count * A->wsize; + long bsize = B->count * B->wsize; + + if (A->sf_size != B->sf_size) fatal("sf_join: sf_size mismatch"); + R = sf_new(A->count + B->count, A->sf_size); + R->count = A->count + B->count; + R->active_count = A->active_count + B->active_count; + intcpy(R->data, A->data, asize); + intcpy(R->data + asize, B->data, bsize); + return R; +} + + +/* sf_append -- append the sets of B to the end of A, and dispose of B */ +pset_family sf_append(A, B) +pset_family A, B; +{ + long asize = A->count * A->wsize; + long bsize = B->count * B->wsize; + + if (A->sf_size != B->sf_size) fatal("sf_append: sf_size mismatch"); + A->capacity = A->count + B->count; + A->data = REALLOC(unsigned int, A->data, (long) A->capacity * A->wsize); + intcpy(A->data + asize, B->data, bsize); + A->count += B->count; + A->active_count += B->active_count; + sf_free(B); + return A; +} + + +/* sf_new -- allocate "num" sets of "size" elements each */ +pset_family sf_new(num, size) +int num, size; +{ + pset_family A; + if (set_family_garbage == NULL) { + A = ALLOC(set_family_t, 1); + } else { + A = set_family_garbage; + set_family_garbage = A->next; + } + A->sf_size = size; + A->wsize = SET_SIZE(size); + A->capacity = num; + A->data = ALLOC(unsigned int, (long) A->capacity * A->wsize); + A->count = 0; + A->active_count = 0; + return A; +} + + +/* sf_save -- create a duplicate copy of a set family */ +pset_family sf_save(A) +register pset_family A; +{ + return sf_copy(sf_new(A->count, A->sf_size), A); +} + + +/* sf_free -- free the storage allocated for a set family */ +void sf_free(A) +pset_family A; +{ + FREE(A->data); + A->next = set_family_garbage; + set_family_garbage = A; +} + + +/* sf_cleanup -- free all of the set families from the garbage list */ +void sf_cleanup() +{ + register pset_family p, pnext; + for(p = set_family_garbage; p != (pset_family) NULL; p = pnext) { + pnext = p->next; + FREE(p); + } + set_family_garbage = (pset_family) NULL; +} + + +/* sf_addset -- add a set to the end of a set family */ +pset_family sf_addset(A, s) +pset_family A; +pset s; +{ + register pset p; + + if (A->count >= A->capacity) { + A->capacity = A->capacity + A->capacity/2 + 1; + A->data = REALLOC(unsigned int, A->data, (long) A->capacity * A->wsize); + } + p = GETSET(A, A->count++); + INLINEset_copy(p, s); + return A; +} + +/* sf_delset -- delete a set from a set family */ +void sf_delset(A, i) +pset_family A; +int i; +{ (void) set_copy(GETSET(A,i), GETSET(A, --A->count));} + +/* sf_print -- print a set_family as a set (list the element numbers) */ +void sf_print(A) +pset_family A; +{ + char *ps1(); + register pset p; + register int i; + foreachi_set(A, i, p) + printf("A[%d] = %s\n", i, ps1(p)); +} + +/* sf_bm_print -- print a set_family as a bit-matrix */ +void sf_bm_print(A) +pset_family A; +{ + char *pbv1(); + register pset p; + register int i; + foreachi_set(A, i, p) + printf("[%4d] %s\n", i, pbv1(p, A->sf_size)); +} + + +/* sf_write -- output a set family in an unintelligable manner */ +void sf_write(fp, A) +FILE *fp; +pset_family A; +{ + register pset p, last; + (void) fprintf(fp, "%d %d\n", A->count, A->sf_size); + foreach_set(A, last, p) + set_write(fp, p); + (void) fflush(fp); +} + + +/* sf_read -- read a set family written by sf_write */ +pset_family sf_read(fp) +FILE *fp; +{ + int i, j; + register pset p, last; + pset_family A; + + (void) fscanf(fp, "%d %d\n", &i, &j); + A = sf_new(i, j); + A->count = i; + foreach_set(A, last, p) { + (void) fscanf(fp, "%x", p); + for(j = 1; j <= LOOP(p); j++) + (void) fscanf(fp, "%x", p+j); + } + return A; +} + + +/* set_write -- output a set in an unintelligable manner */ +void set_write(fp, a) +register FILE *fp; +register pset a; +{ + register int n = LOOP(a), j; + + for(j = 0; j <= n; j++) { + (void) fprintf(fp, "%x ", a[j]); + if ((j+1) % 8 == 0 && j != n) + (void) fprintf(fp, "\n\t"); + } + (void) fprintf(fp, "\n"); +} + + +/* sf_bm_read -- read a set family written by sf_bm_print (almost) */ +pset_family sf_bm_read(fp) +FILE *fp; +{ + int i, j, rows, cols; + register pset pdest; + pset_family A; + + (void) fscanf(fp, "%d %d\n", &rows, &cols); + A = sf_new(rows, cols); + for(i = 0; i < rows; i++) { + pdest = GETSET(A, A->count++); + (void) set_clear(pdest, A->sf_size); + for(j = 0; j < cols; j++) { + switch(getc(fp)) { + case '0': + break; + case '1': + set_insert(pdest, j); + break; + default: + fatal("Error reading set family"); + } + } + if (getc(fp) != '\n') { + fatal("Error reading set family (at end of line)"); + } + } + return A; +} + + + +/* ps1 -- convert a set into a printable string */ +#define largest_string 120 +static char s1[largest_string]; +char *ps1(a) +register pset a; +{ + register int i, num, l, len = 0, n = NELEM(a); + char temp[20]; + bool first = TRUE; + + s1[len++] = '['; + for(i = 0; i < n; i++) + if (is_in_set(a,i)) { + if (! first) + s1[len++] = ','; + first = FALSE; num = i; + /* Generate digits (reverse order) */ + l = 0; do temp[l++] = num % 10 + '0'; while ((num /= 10) > 0); + /* Copy them back in correct order */ + do s1[len++] = temp[--l]; while (l > 0); + if (len > largest_string-15) { + s1[len++] = '.'; s1[len++] = '.'; s1[len++] = '.'; + break; + } + } + + s1[len++] = ']'; + s1[len++] = '\0'; + return s1; +} + +/* pbv1 -- print bit-vector */ +char *pbv1(s, n) +pset s; +int n; +{ + register int i; + for(i = 0; i < n; i++) + s1[i] = is_in_set(s,i) ? '1' : '0'; + s1[n] = '\0'; + return s1; +} + + +/* set_adjcnt -- adjust the counts for a set by "weight" */ +void +set_adjcnt(a, count, weight) +register pset a; +register int *count, weight; +{ + register int i, base; + register unsigned int val; + + for(i = LOOP(a); i > 0; ) { + for(val = a[i], base = --i << LOGBPI; val != 0; base++, val >>= 1) { + if (val & 1) { + count[base] += weight; + } + } + } +} + + + +/* sf_count -- perform a column sum over a set family */ +int *sf_count(A) +pset_family A; +{ + register pset p, last; + register int i, base, *count; + register unsigned int val; + + count = ALLOC(int, A->sf_size); + for(i = A->sf_size - 1; i >= 0; i--) { + count[i] = 0; + } + + foreach_set(A, last, p) { + for(i = LOOP(p); i > 0; ) { + for(val = p[i], base = --i << LOGBPI; val != 0; base++, val >>= 1) { + if (val & 1) { + count[base]++; + } + } + } + } + return count; +} + + +/* sf_count_restricted -- perform a column sum over a set family, restricting + * to only the columns which are in r; also, the columns are weighted by the + * number of elements which are in each row + */ +int *sf_count_restricted(A, r) +pset_family A; +register pset r; +{ + register pset p; + register int i, base, *count; + register unsigned int val; + int weight; + pset last; + + count = ALLOC(int, A->sf_size); + for(i = A->sf_size - 1; i >= 0; i--) { + count[i] = 0; + } + + /* Loop for each set */ + foreach_set(A, last, p) { + weight = 1024 / (set_ord(p) - 1); + for(i = LOOP(p); i > 0; ) { + for(val=p[i]&r[i], base= --i<>= 1) { + if (val & 1) { + count[base] += weight; + } + } + } + } + return count; +} + + +/* + * sf_delc -- delete columns first ... last of A + */ +pset_family sf_delc(A, first, last) +pset_family A; +int first, last; +{ + return sf_delcol(A, first, last-first + 1); +} + + +/* + * sf_addcol -- add columns to a set family; includes a quick check to see + * if there is already enough room (and hence, can avoid copying) + */ +pset_family sf_addcol(A, firstcol, n) +pset_family A; +int firstcol, n; +{ + int maxsize; + + /* Check if adding columns at the end ... */ + if (firstcol == A->sf_size) { + /* If so, check if there is already enough room */ + maxsize = BPI * LOOPINIT(A->sf_size); + if ((A->sf_size + n) <= maxsize) { + A->sf_size += n; + return A; + } + } + return sf_delcol(A, firstcol, -n); +} + +/* + * sf_delcol -- add/delete columns to/from a set family + * + * if n > 0 then n columns starting from firstcol are deleted if n < 0 + * then n blank columns are inserted starting at firstcol + * (i.e., the first new column number is firstcol) + * + * This is done by copying columns in the array which is a relatively + * slow operation. + */ +pset_family sf_delcol(A, firstcol, n) +pset_family A; +register int firstcol, n; +{ + register pset p, last, pdest; + register int i; + pset_family B; + + B = sf_new(A->count, A->sf_size - n); + foreach_set(A, last, p) { + pdest = GETSET(B, B->count++); + INLINEset_clear(pdest, B->sf_size); + for(i = 0; i < firstcol; i++) + if (is_in_set(p, i)) + set_insert(pdest, i); + for(i = n > 0 ? firstcol + n : firstcol; i < A->sf_size; i++) + if (is_in_set(p, i)) + set_insert(pdest, i - n); + } + sf_free(A); + return B; +} + + +/* + * sf_copy_col -- copy column "srccol" from "src" to column "dstcol" of "dst" + */ +pset_family sf_copy_col(dst, dstcol, src, srccol) +pset_family dst, src; +int dstcol, srccol; +{ + register pset last, p, pdest; + register int word_test, word_set; + unsigned int bit_set, bit_test; + + /* CHEAT! form these constants outside the loop */ + word_test = WHICH_WORD(srccol); + bit_test = 1 << WHICH_BIT(srccol); + word_set = WHICH_WORD(dstcol); + bit_set = 1 << WHICH_BIT(dstcol); + + pdest = dst->data; + foreach_set(src, last, p) { + if ((p[word_test] & bit_test) != 0) + pdest[word_set] |= bit_set; +/* + * equivalent code for this is ... + * if (is_in_set(p, srccol)) set_insert(pdest, destcol); + */ + pdest += dst->wsize; + } + return dst; +} + + + +/* + * sf_compress -- delete columns from a matrix + */ +pset_family sf_compress(A, c) +pset_family A; /* will be freed */ +register pset c; +{ + register pset p; + register int i, bcol; + pset_family B; + + /* create a clean set family for the result */ + B = sf_new(A->count, set_ord(c)); + for(i = 0; i < A->count; i++) { + p = GETSET(B, B->count++); + INLINEset_clear(p, B->sf_size); + } + + /* copy each column of A which has a 1 in c */ + bcol = 0; + for(i = 0; i < A->sf_size; i++) { + if (is_in_set(c, i)) { + (void) sf_copy_col(B, bcol++, A, i); + } + } + sf_free(A); + return B; +} + + + +/* + * sf_transpose -- transpose a bit matrix + * + * There are trickier ways of doing this, but this works. + */ +pset_family sf_transpose(A) +pset_family A; +{ + pset_family B; + register pset p; + register int i, j; + + B = sf_new(A->sf_size, A->count); + B->count = A->sf_size; + foreachi_set(B, i, p) { + INLINEset_clear(p, B->sf_size); + } + foreachi_set(A, i, p) { + for(j = 0; j < A->sf_size; j++) { + if (is_in_set(p, j)) { + set_insert(GETSET(B, j), i); + } + } + } + sf_free(A); + return B; +} + + +/* + * sf_permute -- permute the columns of a set_family + * + * permute is an array of integers containing column numbers of A which + * are to be retained. + */ +pset_family sf_permute(A, permute, npermute) +pset_family A; +register int *permute, npermute; +{ + pset_family B; + register pset p, last, pdest; + register int j; + + B = sf_new(A->count, npermute); + B->count = A->count; + foreach_set(B, last, p) + INLINEset_clear(p, npermute); + + pdest = B->data; + foreach_set(A, last, p) { + for(j = 0; j < npermute; j++) + if (is_in_set(p, permute[j])) + set_insert(pdest, j); + pdest += B->wsize; + } + sf_free(A); + return B; +} diff --git a/src/misc/espresso/setc.c b/src/misc/espresso/setc.c new file mode 100644 index 00000000..a6112ebc --- /dev/null +++ b/src/misc/espresso/setc.c @@ -0,0 +1,483 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +/* + setc.c -- massive bit-hacking for performing special "cube"-type + operations on a set + + The basic trick used for binary valued variables is the following: + + If a[w] and b[w] contain a full word of binary variables, then: + + 1) to get the full word of their intersection, we use + + x = a[w] & b[w]; + + + 2) to see if the intersection is null in any variables, we examine + + x = ~(x | x >> 1) & DISJOINT; + + this will have a single 1 in each binary variable for which + the intersection is null. In particular, if this is zero, + then there are no disjoint variables; or, if this is nonzero, + then there is at least one disjoint variable. A "count_ones" + over x will tell in how many variables they have an null + intersection. + + + 3) to get a mask which selects the disjoint variables, we use + + (x | x << 1) + + this provides a selector which can be used to see where + they have an null intersection + + + cdist return distance between two cubes + cdist0 return true if two cubes are distance 0 apart + cdist01 return distance, or 2 if distance exceeds 1 + consensus compute consensus of two cubes distance 1 apart + force_lower expand hack (for now), related to consensus +*/ + +#include "espresso.h" + +/* see if the cube has a full row of 1's (with respect to cof) */ +bool full_row(p, cof) +IN register pcube p, cof; +{ + register int i = LOOP(p); + do if ((p[i] | cof[i]) != cube.fullset[i]) return FALSE; while (--i > 0); + return TRUE; +} + +/* + cdist0 -- return TRUE if a and b are distance 0 apart +*/ + +bool cdist0(a, b) +register pcube a, b; +{ + { /* Check binary variables */ + register int w, last; register unsigned int x; + if ((last = cube.inword) != -1) { + + /* Check the partial word of binary variables */ + x = a[last] & b[last]; + if (~(x | x >> 1) & cube.inmask) + return FALSE; /* disjoint in some variable */ + + /* Check the full words of binary variables */ + for(w = 1; w < last; w++) { + x = a[w] & b[w]; + if (~(x | x >> 1) & DISJOINT) + return FALSE; /* disjoint in some variable */ + } + } + } + + { /* Check the multiple-valued variables */ + register int w, var, last; register pcube mask; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; last = cube.last_word[var]; + for(w = cube.first_word[var]; w <= last; w++) + if (a[w] & b[w] & mask[w]) + goto nextvar; + return FALSE; /* disjoint in this variable */ + nextvar: ; + } + } + return TRUE; +} + +/* + cdist01 -- return the "distance" between two cubes (defined as the + number of null variables in their intersection). If the distance + exceeds 1, the value 2 is returned. +*/ + +int cdist01(a, b) +register pset a, b; +{ + int dist = 0; + + { /* Check binary variables */ + register int w, last; register unsigned int x; + if ((last = cube.inword) != -1) { + + /* Check the partial word of binary variables */ + x = a[last] & b[last]; + if (x = ~ (x | x >> 1) & cube.inmask) + if ((dist = count_ones(x)) > 1) + return 2; + + /* Check the full words of binary variables */ + for(w = 1; w < last; w++) { + x = a[w] & b[w]; + if (x = ~ (x | x >> 1) & DISJOINT) + if (dist == 1 || (dist += count_ones(x)) > 1) + return 2; + } + } + } + + { /* Check the multiple-valued variables */ + register int w, var, last; register pcube mask; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; last = cube.last_word[var]; + for(w = cube.first_word[var]; w <= last; w++) + if (a[w] & b[w] & mask[w]) + goto nextvar; + if (++dist > 1) + return 2; + nextvar: ; + } + } + return dist; +} + +/* + cdist -- return the "distance" between two cubes (defined as the + number of null variables in their intersection). +*/ + +int cdist(a, b) +register pset a, b; +{ + int dist = 0; + + { /* Check binary variables */ + register int w, last; register unsigned int x; + if ((last = cube.inword) != -1) { + + /* Check the partial word of binary variables */ + x = a[last] & b[last]; + if (x = ~ (x | x >> 1) & cube.inmask) + dist = count_ones(x); + + /* Check the full words of binary variables */ + for(w = 1; w < last; w++) { + x = a[w] & b[w]; + if (x = ~ (x | x >> 1) & DISJOINT) + dist += count_ones(x); + } + } + } + + { /* Check the multiple-valued variables */ + register int w, var, last; register pcube mask; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; last = cube.last_word[var]; + for(w = cube.first_word[var]; w <= last; w++) + if (a[w] & b[w] & mask[w]) + goto nextvar; + dist++; + nextvar: ; + } + } + return dist; +} + +/* + force_lower -- Determine which variables of a do not intersect b. +*/ + +pset force_lower(xlower, a, b) +INOUT pset xlower; +IN register pset a, b; +{ + + { /* Check binary variables (if any) */ + register int w, last; register unsigned int x; + if ((last = cube.inword) != -1) { + + /* Check the partial word of binary variables */ + x = a[last] & b[last]; + if (x = ~(x | x >> 1) & cube.inmask) + xlower[last] |= (x | (x << 1)) & a[last]; + + /* Check the full words of binary variables */ + for(w = 1; w < last; w++) { + x = a[w] & b[w]; + if (x = ~(x | x >> 1) & DISJOINT) + xlower[w] |= (x | (x << 1)) & a[w]; + } + } + } + + { /* Check the multiple-valued variables */ + register int w, var, last; register pcube mask; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; last = cube.last_word[var]; + for(w = cube.first_word[var]; w <= last; w++) + if (a[w] & b[w] & mask[w]) + goto nextvar; + for(w = cube.first_word[var]; w <= last; w++) + xlower[w] |= a[w] & mask[w]; + nextvar: ; + } + } + return xlower; +} + +/* + consensus -- multiple-valued consensus + + Although this looks very messy, the idea is to compute for r the + "and" of the cubes a and b for each variable, unless the "and" is + null in a variable, in which case the "or" of a and b is computed + for this variable. + + Because we don't check how many variables are null in the + intersection of a and b, the returned value for r really only + represents the consensus when a and b are distance 1 apart. +*/ + +void consensus(r, a, b) +INOUT pcube r; +IN register pcube a, b; +{ + INLINEset_clear(r, cube.size); + + { /* Check binary variables (if any) */ + register int w, last; register unsigned int x; + if ((last = cube.inword) != -1) { + + /* Check the partial word of binary variables */ + r[last] = x = a[last] & b[last]; + if (x = ~(x | x >> 1) & cube.inmask) + r[last] |= (x | (x << 1)) & (a[last] | b[last]); + + /* Check the full words of binary variables */ + for(w = 1; w < last; w++) { + r[w] = x = a[w] & b[w]; + if (x = ~(x | x >> 1) & DISJOINT) + r[w] |= (x | (x << 1)) & (a[w] | b[w]); + } + } + } + + + { /* Check the multiple-valued variables */ + bool empty; int var; unsigned int x; + register int w, last; register pcube mask; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; + last = cube.last_word[var]; + empty = TRUE; + for(w = cube.first_word[var]; w <= last; w++) + if (x = a[w] & b[w] & mask[w]) + empty = FALSE, r[w] |= x; + if (empty) + for(w = cube.first_word[var]; w <= last; w++) + r[w] |= mask[w] & (a[w] | b[w]); + } + } +} + +/* + cactive -- return the index of the single active variable in + the cube, or return -1 if there are none or more than 2. +*/ + +int cactive(a) +register pcube a; +{ + int active = -1, dist = 0, bit_index(); + + { /* Check binary variables */ + register int w, last; + register unsigned int x; + if ((last = cube.inword) != -1) { + + /* Check the partial word of binary variables */ + x = a[last]; + if (x = ~ (x & x >> 1) & cube.inmask) { + if ((dist = count_ones(x)) > 1) + return -1; /* more than 2 active variables */ + active = (last-1)*(BPI/2) + bit_index(x) / 2; + } + + /* Check the full words of binary variables */ + for(w = 1; w < last; w++) { + x = a[w]; + if (x = ~ (x & x >> 1) & DISJOINT) { + if ((dist += count_ones(x)) > 1) + return -1; /* more than 2 active variables */ + active = (w-1)*(BPI/2) + bit_index(x) / 2; + } + } + } + } + + { /* Check the multiple-valued variables */ + register int w, var, last; + register pcube mask; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; + last = cube.last_word[var]; + for(w = cube.first_word[var]; w <= last; w++) + if (mask[w] & ~ a[w]) { + if (++dist > 1) + return -1; + active = var; + break; + } + } + } + return active; +} + +/* + ccommon -- return TRUE if a and b are share "active" variables + active variables include variables that are empty; +*/ + +bool ccommon(a, b, cof) +register pcube a, b, cof; +{ + { /* Check binary variables */ + int last; + register int w; + register unsigned int x, y; + if ((last = cube.inword) != -1) { + + /* Check the partial word of binary variables */ + x = a[last] | cof[last]; + y = b[last] | cof[last]; + if (~(x & x>>1) & ~(y & y>>1) & cube.inmask) + return TRUE; + + /* Check the full words of binary variables */ + for(w = 1; w < last; w++) { + x = a[w] | cof[w]; + y = b[w] | cof[w]; + if (~(x & x>>1) & ~(y & y>>1) & DISJOINT) + return TRUE; + } + } + } + + { /* Check the multiple-valued variables */ + int var; + register int w, last; + register pcube mask; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; last = cube.last_word[var]; + /* Check for some part missing from a */ + for(w = cube.first_word[var]; w <= last; w++) + if (mask[w] & ~a[w] & ~cof[w]) { + + /* If so, check for some part missing from b */ + for(w = cube.first_word[var]; w <= last; w++) + if (mask[w] & ~b[w] & ~cof[w]) + return TRUE; /* both active */ + break; + } + } + } + return FALSE; +} + +/* + These routines compare two sets (cubes) for the qsort() routine and + return: + + -1 if set a is to precede set b + 0 if set a and set b are equal + 1 if set a is to follow set b + + Usually the SIZE field of the set is assumed to contain the size + of the set (which will save recomputing the set size during the + sort). For distance-1 merging, the global variable cube.temp[0] is + a mask which mask's-out the merging variable. +*/ + +/* descend -- comparison for descending sort on set size */ +int descend(a, b) +pset *a, *b; +{ + register pset a1 = *a, b1 = *b; + if (SIZE(a1) > SIZE(b1)) return -1; + else if (SIZE(a1) < SIZE(b1)) return 1; + else { + register int i = LOOP(a1); + do + if (a1[i] > b1[i]) return -1; else if (a1[i] < b1[i]) return 1; + while (--i > 0); + } + return 0; +} + +/* ascend -- comparison for ascending sort on set size */ +int ascend(a, b) +pset *a, *b; +{ + register pset a1 = *a, b1 = *b; + if (SIZE(a1) > SIZE(b1)) return 1; + else if (SIZE(a1) < SIZE(b1)) return -1; + else { + register int i = LOOP(a1); + do + if (a1[i] > b1[i]) return 1; else if (a1[i] < b1[i]) return -1; + while (--i > 0); + } + return 0; +} + + +/* lex_order -- comparison for "lexical" ordering of cubes */ +int lex_order(a, b) +pset *a, *b; +{ + register pset a1 = *a, b1 = *b; + register int i = LOOP(a1); + do + if (a1[i] > b1[i]) return -1; else if (a1[i] < b1[i]) return 1; + while (--i > 0); + return 0; +} + + +/* d1_order -- comparison for distance-1 merge routine */ +int d1_order(a, b) +pset *a, *b; +{ + register pset a1 = *a, b1 = *b, c1 = cube.temp[0]; + register int i = LOOP(a1); + register unsigned int x1, x2; + do + if ((x1 = a1[i] | c1[i]) > (x2 = b1[i] | c1[i])) return -1; + else if (x1 < x2) return 1; + while (--i > 0); + return 0; +} + + +/* desc1 -- comparison (without indirection) for descending sort */ +/* also has effect of handling NULL pointers,and a NULL pointer has smallest +order */ +int desc1(a, b) +register pset a, b; +{ + if (a == (pset) NULL) + return (b == (pset) NULL) ? 0 : 1; + else if (b == (pset) NULL) + return -1; + if (SIZE(a) > SIZE(b)) return -1; + else if (SIZE(a) < SIZE(b)) return 1; + else { + register int i = LOOP(a); + do + if (a[i] > b[i]) return -1; else if (a[i] < b[i]) return 1; + while (--i > 0); + } + return 0; +} diff --git a/src/misc/espresso/sharp.c b/src/misc/espresso/sharp.c new file mode 100644 index 00000000..53435078 --- /dev/null +++ b/src/misc/espresso/sharp.c @@ -0,0 +1,247 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +/* + sharp.c -- perform sharp, disjoint sharp, and intersection +*/ + +#include "espresso.h" + +long start_time; + + +/* cv_sharp -- form the sharp product between two covers */ +pcover cv_sharp(A, B) +pcover A, B; +{ + pcube last, p; + pcover T; + + T = new_cover(0); + foreach_set(A, last, p) + T = sf_union(T, cb_sharp(p, B)); + return T; +} + + +/* cb_sharp -- form the sharp product between a cube and a cover */ +pcover cb_sharp(c, T) +pcube c; +pcover T; +{ + if (T->count == 0) { + T = sf_addset(new_cover(1), c); + } else { + start_time = ptime(); + T = cb_recur_sharp(c, T, 0, T->count-1, 0); + } + return T; +} + + +/* recursive formulation to provide balanced merging */ +pcover cb_recur_sharp(c, T, first, last, level) +pcube c; +pcover T; +int first, last, level; +{ + pcover temp, left, right; + int middle; + + if (first == last) { + temp = sharp(c, GETSET(T, first)); + } else { + middle = (first + last) / 2; + left = cb_recur_sharp(c, T, first, middle, level+1); + right = cb_recur_sharp(c, T, middle+1, last, level+1); + temp = cv_intersect(left, right); + if ((debug & SHARP) && level < 4) { + printf("# SHARP[%d]: %4d = %4d x %4d, time = %s\n", + level, temp->count, left->count, right->count, + print_time(ptime() - start_time)); + (void) fflush(stdout); + } + free_cover(left); + free_cover(right); + } + return temp; +} + + +/* sharp -- form the sharp product between two cubes */ +pcover sharp(a, b) +pcube a, b; +{ + register int var; + register pcube d=cube.temp[0], temp=cube.temp[1], temp1=cube.temp[2]; + pcover r = new_cover(cube.num_vars); + + if (cdist0(a, b)) { + set_diff(d, a, b); + for(var = 0; var < cube.num_vars; var++) { + if (! setp_empty(set_and(temp, d, cube.var_mask[var]))) { + set_diff(temp1, a, cube.var_mask[var]); + set_or(GETSET(r, r->count++), temp, temp1); + } + } + } else { + r = sf_addset(r, a); + } + return r; +} + +pcover make_disjoint(A) +pcover A; +{ + pcover R, new; + register pset last, p; + + R = new_cover(0); + foreach_set(A, last, p) { + new = cb_dsharp(p, R); + R = sf_append(R, new); + } + return R; +} + + +/* cv_dsharp -- disjoint-sharp product between two covers */ +pcover cv_dsharp(A, B) +pcover A, B; +{ + register pcube last, p; + pcover T; + + T = new_cover(0); + foreach_set(A, last, p) { + T = sf_union(T, cb_dsharp(p, B)); + } + return T; +} + + +/* cb1_dsharp -- disjoint-sharp product between a cover and a cube */ +pcover cb1_dsharp(T, c) +pcover T; +pcube c; +{ + pcube last, p; + pcover R; + + R = new_cover(T->count); + foreach_set(T, last, p) { + R = sf_union(R, dsharp(p, c)); + } + return R; +} + + +/* cb_dsharp -- disjoint-sharp product between a cube and a cover */ +pcover cb_dsharp(c, T) +pcube c; +pcover T; +{ + pcube last, p; + pcover Y, Y1; + + if (T->count == 0) { + Y = sf_addset(new_cover(1), c); + } else { + Y = new_cover(T->count); + set_copy(GETSET(Y,Y->count++), c); + foreach_set(T, last, p) { + Y1 = cb1_dsharp(Y, p); + free_cover(Y); + Y = Y1; + } + } + return Y; +} + + +/* dsharp -- form the disjoint-sharp product between two cubes */ +pcover dsharp(a, b) +pcube a, b; +{ + register pcube mask, diff, and, temp, temp1 = cube.temp[0]; + int var; + pcover r; + + r = new_cover(cube.num_vars); + + if (cdist0(a, b)) { + diff = set_diff(new_cube(), a, b); + and = set_and(new_cube(), a, b); + mask = new_cube(); + for(var = 0; var < cube.num_vars; var++) { + /* check if position var of "a and not b" is not empty */ + if (! setp_disjoint(diff, cube.var_mask[var])) { + + /* coordinate var equals the difference between a and b */ + temp = GETSET(r, r->count++); + (void) set_and(temp, diff, cube.var_mask[var]); + + /* coordinates 0 ... var-1 equal the intersection */ + INLINEset_and(temp1, and, mask); + INLINEset_or(temp, temp, temp1); + + /* coordinates var+1 .. cube.num_vars equal a */ + set_or(mask, mask, cube.var_mask[var]); + INLINEset_diff(temp1, a, mask); + INLINEset_or(temp, temp, temp1); + } + } + free_cube(diff); + free_cube(and); + free_cube(mask); + } else { + r = sf_addset(r, a); + } + return r; +} + +/* cv_intersect -- form the intersection of two covers */ + +#define MAGIC 500 /* save 500 cubes before containment */ + +pcover cv_intersect(A, B) +pcover A, B; +{ + register pcube pi, pj, lasti, lastj, pt; + pcover T, Tsave = NULL; + + /* How large should each temporary result cover be ? */ + T = new_cover(MAGIC); + pt = T->data; + + /* Form pairwise intersection of each cube of A with each cube of B */ + foreach_set(A, lasti, pi) { + foreach_set(B, lastj, pj) { + if (cdist0(pi, pj)) { + (void) set_and(pt, pi, pj); + if (++T->count >= T->capacity) { + if (Tsave == NULL) + Tsave = sf_contain(T); + else + Tsave = sf_union(Tsave, sf_contain(T)); + T = new_cover(MAGIC); + pt = T->data; + } else + pt += T->wsize; + } + } + } + + + if (Tsave == NULL) + Tsave = sf_contain(T); + else + Tsave = sf_union(Tsave, sf_contain(T)); + return Tsave; +} diff --git a/src/misc/espresso/sminterf.c b/src/misc/espresso/sminterf.c new file mode 100644 index 00000000..50a6db4e --- /dev/null +++ b/src/misc/espresso/sminterf.c @@ -0,0 +1,44 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +#include "espresso.h" + + +pset +do_sm_minimum_cover(A) +pset_family A; +{ + sm_matrix *M; + sm_row *sparse_cover; + sm_element *pe; + pset cover; + register int i, base, rownum; + register unsigned val; + register pset last, p; + + M = sm_alloc(); + rownum = 0; + foreach_set(A, last, p) { + foreach_set_element(p, i, val, base) { + (void) sm_insert(M, rownum, base); + } + rownum++; + } + + sparse_cover = sm_minimum_cover(M, NIL(int), 1, 0); + sm_free(M); + + cover = set_new(A->sf_size); + sm_foreach_row_element(sparse_cover, pe) { + set_insert(cover, pe->col_num); + } + sm_row_free(sparse_cover); + + return cover; +} diff --git a/src/misc/espresso/solution.c b/src/misc/espresso/solution.c new file mode 100644 index 00000000..26119185 --- /dev/null +++ b/src/misc/espresso/solution.c @@ -0,0 +1,114 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +#include "mincov_int.h" + + +solution_t * +solution_alloc() +{ + solution_t *sol; + + sol = ALLOC(solution_t, 1); + sol->cost = 0; + sol->row = sm_row_alloc(); + return sol; +} + + +void +solution_free(sol) +solution_t *sol; +{ + sm_row_free(sol->row); + FREE(sol); +} + + +solution_t * +solution_dup(sol) +solution_t *sol; +{ + solution_t *new_sol; + + new_sol = ALLOC(solution_t, 1); + new_sol->cost = sol->cost; + new_sol->row = sm_row_dup(sol->row); + return new_sol; +} + + +void +solution_add(sol, weight, col) +solution_t *sol; +int *weight; +int col; +{ + (void) sm_row_insert(sol->row, col); + sol->cost += WEIGHT(weight, col); +} + + +void +solution_accept(sol, A, weight, col) +solution_t *sol; +sm_matrix *A; +int *weight; +int col; +{ + register sm_element *p, *pnext; + sm_col *pcol; + + solution_add(sol, weight, col); + + /* delete rows covered by this column */ + pcol = sm_get_col(A, col); + for(p = pcol->first_row; p != 0; p = pnext) { + pnext = p->next_row; /* grab it before it disappears */ + sm_delrow(A, p->row_num); + } +} + + +/* ARGSUSED */ +void +solution_reject(sol, A, weight, col) +solution_t *sol; +sm_matrix *A; +int *weight; +int col; +{ + sm_delcol(A, col); +} + + +solution_t * +solution_choose_best(best1, best2) +solution_t *best1, *best2; +{ + if (best1 != NIL(solution_t)) { + if (best2 != NIL(solution_t)) { + if (best1->cost <= best2->cost) { + solution_free(best2); + return best1; + } else { + solution_free(best1); + return best2; + } + } else { + return best1; + } + } else { + if (best2 != NIL(solution_t)) { + return best2; + } else { + return NIL(solution_t); + } + } +} diff --git a/src/misc/espresso/sparse.c b/src/misc/espresso/sparse.c new file mode 100644 index 00000000..137ce7c1 --- /dev/null +++ b/src/misc/espresso/sparse.c @@ -0,0 +1,146 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +/* + module: sparse.c + + make_sparse is a last-step cleanup to reduce the total number + of literals in the cover. + + This is done by reducing the "sparse" variables (using a modified + version of irredundant rather than reduce), followed by expanding + the "dense" variables (using modified version of expand). +*/ + +#include "espresso.h" + +pcover make_sparse(F, D, R) +pcover F, D, R; +{ + cost_t cost, best_cost; + + cover_cost(F, &best_cost); + + do { + EXECUTE(F = mv_reduce(F, D), MV_REDUCE_TIME, F, cost); + if (cost.total == best_cost.total) + break; + copy_cost(&cost, &best_cost); + + EXECUTE(F = expand(F, R, TRUE), RAISE_IN_TIME, F, cost); + if (cost.total == best_cost.total) + break; + copy_cost(&cost, &best_cost); + } while (force_irredundant); + + return F; +} + +/* + mv_reduce -- perform an "optimal" reduction of the variables which + we desire to be sparse + + This could be done using "reduce" and then saving just the desired + part of the reduction. Instead, this version uses IRRED to find + which cubes of an output are redundant. Note that this gets around + the cube-ordering problem. + + In normal use, it is expected that the cover is irredundant and + hence no cubes will be reduced to the empty cube (however, this is + checked for and such cubes will be deleted) +*/ + +pcover +mv_reduce(F, D) +pcover F, D; +{ + register int i, var; + register pcube p, p1, last; + int index; + pcover F1, D1; + pcube *F_cube_table; + + /* loop for each multiple-valued variable */ + for(var = 0; var < cube.num_vars; var++) { + + if (cube.sparse[var]) { + + /* loop for each part of the variable */ + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + + /* remember mapping of F1 cubes back to F cubes */ + F_cube_table = ALLOC(pcube, F->count); + + /* 'cofactor' against part #i of variable #var */ + F1 = new_cover(F->count); + foreach_set(F, last, p) { + if (is_in_set(p, i)) { + F_cube_table[F1->count] = p; + p1 = GETSET(F1, F1->count++); + (void) set_diff(p1, p, cube.var_mask[var]); + set_insert(p1, i); + } + } + + /* 'cofactor' against part #i of variable #var */ + /* not really necessary -- just more efficient ? */ + D1 = new_cover(D->count); + foreach_set(D, last, p) { + if (is_in_set(p, i)) { + p1 = GETSET(D1, D1->count++); + (void) set_diff(p1, p, cube.var_mask[var]); + set_insert(p1, i); + } + } + + mark_irredundant(F1, D1); + + /* now remove part i from cubes which are redundant */ + index = 0; + foreach_set(F1, last, p1) { + if (! TESTP(p1, ACTIVE)) { + p = F_cube_table[index]; + + /* don't reduce a variable which is full + * (unless it is the output variable) + */ + if (var == cube.num_vars-1 || + ! setp_implies(cube.var_mask[var], p)) { + set_remove(p, i); + } + RESET(p, PRIME); + } + index++; + } + + free_cover(F1); + free_cover(D1); + FREE(F_cube_table); + } + } + } + + /* Check if any cubes disappeared */ + (void) sf_active(F); + for(var = 0; var < cube.num_vars; var++) { + if (cube.sparse[var]) { + foreach_active_set(F, last, p) { + if (setp_disjoint(p, cube.var_mask[var])) { + RESET(p, ACTIVE); + F->active_count--; + } + } + } + } + + if (F->count != F->active_count) { + F = sf_inactive(F); + } + return F; +} diff --git a/src/misc/espresso/sparse.h b/src/misc/espresso/sparse.h new file mode 100644 index 00000000..212a32ed --- /dev/null +++ b/src/misc/espresso/sparse.h @@ -0,0 +1,135 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +#ifndef SPARSE_H +#define SPARSE_H + +/* + * sparse.h -- sparse matrix package header file + */ + +typedef struct sm_element_struct sm_element; +typedef struct sm_row_struct sm_row; +typedef struct sm_col_struct sm_col; +typedef struct sm_matrix_struct sm_matrix; + + +/* + * sparse matrix element + */ +struct sm_element_struct { + int row_num; /* row number of this element */ + int col_num; /* column number of this element */ + sm_element *next_row; /* next row in this column */ + sm_element *prev_row; /* previous row in this column */ + sm_element *next_col; /* next column in this row */ + sm_element *prev_col; /* previous column in this row */ + char *user_word; /* user-defined word */ +}; + + +/* + * row header + */ +struct sm_row_struct { + int row_num; /* the row number */ + int length; /* number of elements in this row */ + int flag; /* user-defined word */ + sm_element *first_col; /* first element in this row */ + sm_element *last_col; /* last element in this row */ + sm_row *next_row; /* next row (in sm_matrix linked list) */ + sm_row *prev_row; /* previous row (in sm_matrix linked list) */ + char *user_word; /* user-defined word */ +}; + + +/* + * column header + */ +struct sm_col_struct { + int col_num; /* the column number */ + int length; /* number of elements in this column */ + int flag; /* user-defined word */ + sm_element *first_row; /* first element in this column */ + sm_element *last_row; /* last element in this column */ + sm_col *next_col; /* next column (in sm_matrix linked list) */ + sm_col *prev_col; /* prev column (in sm_matrix linked list) */ + char *user_word; /* user-defined word */ +}; + + +/* + * A sparse matrix + */ +struct sm_matrix_struct { + sm_row **rows; /* pointer to row headers (by row #) */ + int rows_size; /* alloc'ed size of above array */ + sm_col **cols; /* pointer to column headers (by col #) */ + int cols_size; /* alloc'ed size of above array */ + sm_row *first_row; /* first row (linked list of all rows) */ + sm_row *last_row; /* last row (linked list of all rows) */ + int nrows; /* number of rows */ + sm_col *first_col; /* first column (linked list of columns) */ + sm_col *last_col; /* last column (linked list of columns) */ + int ncols; /* number of columns */ + char *user_word; /* user-defined word */ +}; + + +#define sm_get_col(A, colnum) \ + (((colnum) >= 0 && (colnum) < (A)->cols_size) ? \ + (A)->cols[colnum] : (sm_col *) 0) + +#define sm_get_row(A, rownum) \ + (((rownum) >= 0 && (rownum) < (A)->rows_size) ? \ + (A)->rows[rownum] : (sm_row *) 0) + +#define sm_foreach_row(A, prow) \ + for(prow = A->first_row; prow != 0; prow = prow->next_row) + +#define sm_foreach_col(A, pcol) \ + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) + +#define sm_foreach_row_element(prow, p) \ + for(p = prow->first_col; p != 0; p = p->next_col) + +#define sm_foreach_col_element(pcol, p) \ + for(p = pcol->first_row; p != 0; p = p->next_row) + +#define sm_put(x, val) \ + (x->user_word = (char *) val) + +#define sm_get(type, x) \ + ((type) (x->user_word)) + +extern sm_matrix *sm_alloc(), *sm_alloc_size(), *sm_dup(); +extern void sm_free(), sm_delrow(), sm_delcol(), sm_resize(); +extern void sm_write(), sm_print(), sm_dump(), sm_cleanup(); +extern void sm_copy_row(), sm_copy_col(); +extern void sm_remove(), sm_remove_element(); +extern sm_element *sm_insert(), *sm_find(); +extern sm_row *sm_longest_row(); +extern sm_col *sm_longest_col(); +extern int sm_read(), sm_read_compressed(); + +extern sm_row *sm_row_alloc(), *sm_row_dup(), *sm_row_and(); +extern void sm_row_free(), sm_row_remove(), sm_row_print(); +extern sm_element *sm_row_insert(), *sm_row_find(); +extern int sm_row_contains(), sm_row_intersects(); +extern int sm_row_compare(), sm_row_hash(); + +extern sm_col *sm_col_alloc(), *sm_col_dup(), *sm_col_and(); +extern void sm_col_free(), sm_col_remove(), sm_col_print(); +extern sm_element *sm_col_insert(), *sm_col_find(); +extern int sm_col_contains(), sm_col_intersects(); +extern int sm_col_compare(), sm_col_hash(); + +extern int sm_row_dominance(), sm_col_dominance(), sm_block_partition(); + +#endif diff --git a/src/misc/espresso/sparse_int.h b/src/misc/espresso/sparse_int.h new file mode 100644 index 00000000..49b2509a --- /dev/null +++ b/src/misc/espresso/sparse_int.h @@ -0,0 +1,121 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +//#include "port.h" +//#include "utility.h" +#include "sparse.h" + +#include "util_hack.h" // added + + + +/* + * sorted, double-linked list insertion + * + * type: object type + * + * first, last: fields (in header) to head and tail of the list + * count: field (in header) of length of the list + * + * next, prev: fields (in object) to link next and previous objects + * value: field (in object) which controls the order + * + * newval: value field for new object + * e: an object to use if insertion needed (set to actual value used) + */ + +#define sorted_insert(type, first, last, count, next, prev, value, newval, e) \ + if (last == 0) { \ + e->value = newval; \ + first = e; \ + last = e; \ + e->next = 0; \ + e->prev = 0; \ + count++; \ + } else if (last->value < newval) { \ + e->value = newval; \ + last->next = e; \ + e->prev = last; \ + last = e; \ + e->next = 0; \ + count++; \ + } else if (first->value > newval) { \ + e->value = newval; \ + first->prev = e; \ + e->next = first; \ + first = e; \ + e->prev = 0; \ + count++; \ + } else { \ + type *p; \ + for(p = first; p->value < newval; p = p->next) \ + ; \ + if (p->value > newval) { \ + e->value = newval; \ + p = p->prev; \ + p->next->prev = e; \ + e->next = p->next; \ + p->next = e; \ + e->prev = p; \ + count++; \ + } else { \ + e = p; \ + } \ + } + + +/* + * double linked-list deletion + */ +#define dll_unlink(p, first, last, next, prev, count) { \ + if (p->prev == 0) { \ + first = p->next; \ + } else { \ + p->prev->next = p->next; \ + } \ + if (p->next == 0) { \ + last = p->prev; \ + } else { \ + p->next->prev = p->prev; \ + } \ + count--; \ +} + + +#ifdef FAST_AND_LOOSE +extern sm_element *sm_element_freelist; +extern sm_row *sm_row_freelist; +extern sm_col *sm_col_freelist; + +#define sm_element_alloc(newobj) \ + if (sm_element_freelist == NIL(sm_element)) { \ + newobj = ALLOC(sm_element, 1); \ + } else { \ + newobj = sm_element_freelist; \ + sm_element_freelist = sm_element_freelist->next_col; \ + } \ + newobj->user_word = NIL(char); \ + +#define sm_element_free(e) \ + (e->next_col = sm_element_freelist, sm_element_freelist = e) + +#else + +#define sm_element_alloc(newobj) \ + newobj = ALLOC(sm_element, 1); \ + newobj->user_word = NIL(char); +#define sm_element_free(e) \ + FREE(e) +#endif + + +extern void sm_row_remove_element(); +extern void sm_col_remove_element(); + +/* LINTLIBRARY */ diff --git a/src/misc/espresso/unate.c b/src/misc/espresso/unate.c new file mode 100644 index 00000000..bd71207f --- /dev/null +++ b/src/misc/espresso/unate.c @@ -0,0 +1,441 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +/* + * unate.c -- routines for dealing with unate functions + */ + +#include "espresso.h" + +static pset_family abs_covered(); +static pset_family abs_covered_many(); +static int abs_select_restricted(); + +pcover map_cover_to_unate(T) +pcube *T; +{ + register unsigned int word_test, word_set, bit_test, bit_set; + register pcube p, pA; + pset_family A; + pcube *T1; + int ncol, i; + + A = sf_new(CUBELISTSIZE(T), cdata.vars_unate); + A->count = CUBELISTSIZE(T); + foreachi_set(A, i, p) { + (void) set_clear(p, A->sf_size); + } + ncol = 0; + + for(i = 0; i < cube.size; i++) { + if (cdata.part_zeros[i] > 0) { + assert(ncol <= cdata.vars_unate); + + /* Copy a column from T to A */ + word_test = WHICH_WORD(i); + bit_test = 1 << WHICH_BIT(i); + word_set = WHICH_WORD(ncol); + bit_set = 1 << WHICH_BIT(ncol); + + pA = A->data; + for(T1 = T+2; (p = *T1++) != 0; ) { + if ((p[word_test] & bit_test) == 0) { + pA[word_set] |= bit_set; + } + pA += A->wsize; + } + + ncol++; + } + } + + return A; +} + +pcover map_unate_to_cover(A) +pset_family A; +{ + register int i, ncol, lp; + register pcube p, pB; + int var, nunate, *unate; + pcube last; + pset_family B; + + B = sf_new(A->count, cube.size); + B->count = A->count; + + /* Find the unate variables */ + unate = ALLOC(int, cube.num_vars); + nunate = 0; + for(var = 0; var < cube.num_vars; var++) { + if (cdata.is_unate[var]) { + unate[nunate++] = var; + } + } + + /* Loop for each set of A */ + pB = B->data; + foreach_set(A, last, p) { + + /* Initialize this set of B */ + INLINEset_fill(pB, cube.size); + + /* Now loop for the unate variables; if the part is in A, + * then this variable of B should be a single 1 in the unate + * part. + */ + for(ncol = 0; ncol < nunate; ncol++) { + if (is_in_set(p, ncol)) { + lp = cube.last_part[unate[ncol]]; + for(i = cube.first_part[unate[ncol]]; i <= lp; i++) { + if (cdata.part_zeros[i] == 0) { + set_remove(pB, i); + } + } + } + } + pB += B->wsize; + } + + FREE(unate); + return B; +} + +/* + * unate_compl + */ + +pset_family unate_compl(A) +pset_family A; +{ + register pset p, last; + + /* Make sure A is single-cube containment minimal */ +/* A = sf_rev_contain(A);*/ + + foreach_set(A, last, p) { + PUTSIZE(p, set_ord(p)); + } + + /* Recursively find the complement */ + A = unate_complement(A); + + /* Now, we can guarantee a minimal result by containing the result */ + A = sf_rev_contain(A); + return A; +} + + +/* + * Assume SIZE(p) records the size of each set + */ +pset_family unate_complement(A) +pset_family A; /* disposes of A */ +{ + pset_family Abar; + register pset p, p1, restrict; + register int i; + int max_i, min_set_ord, j; + + /* Check for no sets in the matrix -- complement is the universe */ + if (A->count == 0) { + sf_free(A); + Abar = sf_new(1, A->sf_size); + (void) set_clear(GETSET(Abar, Abar->count++), A->sf_size); + + /* Check for a single set in the maxtrix -- compute de Morgan complement */ + } else if (A->count == 1) { + p = A->data; + Abar = sf_new(A->sf_size, A->sf_size); + for(i = 0; i < A->sf_size; i++) { + if (is_in_set(p, i)) { + p1 = set_clear(GETSET(Abar, Abar->count++), A->sf_size); + set_insert(p1, i); + } + } + sf_free(A); + + } else { + + /* Select splitting variable as the variable which belongs to a set + * of the smallest size, and which has greatest column count + */ + restrict = set_new(A->sf_size); + min_set_ord = A->sf_size + 1; + foreachi_set(A, i, p) { + if (SIZE(p) < min_set_ord) { + set_copy(restrict, p); + min_set_ord = SIZE(p); + } else if (SIZE(p) == min_set_ord) { + set_or(restrict, restrict, p); + } + } + + /* Check for no data (shouldn't happen ?) */ + if (min_set_ord == 0) { + A->count = 0; + Abar = A; + + /* Check for "essential" columns */ + } else if (min_set_ord == 1) { + Abar = unate_complement(abs_covered_many(A, restrict)); + sf_free(A); + foreachi_set(Abar, i, p) { + set_or(p, p, restrict); + } + + /* else, recur as usual */ + } else { + max_i = abs_select_restricted(A, restrict); + + /* Select those rows of A which are not covered by max_i, + * recursively find all minimal covers of these rows, and + * then add back in max_i + */ + Abar = unate_complement(abs_covered(A, max_i)); + foreachi_set(Abar, i, p) { + set_insert(p, max_i); + } + + /* Now recur on A with all zero's on column max_i */ + foreachi_set(A, i, p) { + if (is_in_set(p, max_i)) { + set_remove(p, max_i); + j = SIZE(p) - 1; + PUTSIZE(p, j); + } + } + + Abar = sf_append(Abar, unate_complement(A)); + } + set_free(restrict); + } + + return Abar; +} + +pset_family exact_minimum_cover(T) +IN pset_family T; +{ + register pset p, last, p1; + register int i, n; + int lev, lvl; + pset nlast; + pset_family temp; + long start = ptime(); + struct { + pset_family sf; + int level; + } stack[32]; /* 32 suffices for 2 ** 32 cubes ! */ + + if (T->count <= 0) + return sf_new(1, T->sf_size); + for(n = T->count, lev = 0; n != 0; n >>= 1, lev++) ; + + /* A simple heuristic ordering */ + T = lex_sort(sf_save(T)); + + /* Push a full set on the stack to get things started */ + n = 1; + stack[0].sf = sf_new(1, T->sf_size); + stack[0].level = lev; + set_fill(GETSET(stack[0].sf, stack[0].sf->count++), T->sf_size); + + nlast = GETSET(T, T->count - 1); + foreach_set(T, last, p) { + + /* "unstack" the set into a family */ + temp = sf_new(set_ord(p), T->sf_size); + for(i = 0; i < T->sf_size; i++) + if (is_in_set(p, i)) { + p1 = set_fill(GETSET(temp, temp->count++), T->sf_size); + set_remove(p1, i); + } + stack[n].sf = temp; + stack[n++].level = lev; + + /* Pop the stack and perform (leveled) intersections */ + while (n > 1 && (stack[n-1].level==stack[n-2].level || p == nlast)) { + temp = unate_intersect(stack[n-1].sf, stack[n-2].sf, FALSE); + lvl = MIN(stack[n-1].level, stack[n-2].level) - 1; + if (debug & MINCOV && lvl < 10) { + printf("# EXACT_MINCOV[%d]: %4d = %4d x %4d, time = %s\n", + lvl, temp->count, stack[n-1].sf->count, + stack[n-2].sf->count, print_time(ptime() - start)); + (void) fflush(stdout); + } + sf_free(stack[n-2].sf); + sf_free(stack[n-1].sf); + stack[n-2].sf = temp; + stack[n-2].level = lvl; + n--; + } + } + + temp = stack[0].sf; + p1 = set_fill(set_new(T->sf_size), T->sf_size); + foreach_set(temp, last, p) + INLINEset_diff(p, p1, p); + set_free(p1); + if (debug & MINCOV1) { + printf("MINCOV: family of all minimal coverings is\n"); + sf_print(temp); + } + sf_free(T); /* this is the copy of T we made ... */ + return temp; +} + +/* + * unate_intersect -- intersect two unate covers + * + * If largest_only is TRUE, then only the largest cube(s) are returned + */ + +#define MAGIC 500 /* save 500 cubes before containment */ + +pset_family unate_intersect(A, B, largest_only) +pset_family A, B; +bool largest_only; +{ + register pset pi, pj, lasti, lastj, pt; + pset_family T, Tsave; + bool save; + int maxord, ord; + + /* How large should each temporary result cover be ? */ + T = sf_new(MAGIC, A->sf_size); + Tsave = NULL; + maxord = 0; + pt = T->data; + + /* Form pairwise intersection of each set of A with each cube of B */ + foreach_set(A, lasti, pi) { + + foreach_set(B, lastj, pj) { + + save = set_andp(pt, pi, pj); + + /* Check if we want the largest only */ + if (save && largest_only) { + if ((ord = set_ord(pt)) > maxord) { + /* discard Tsave and T */ + if (Tsave != NULL) { + sf_free(Tsave); + Tsave = NULL; + } + pt = T->data; + T->count = 0; + /* Re-create pt (which was just thrown away) */ + (void) set_and(pt, pi, pj); + maxord = ord; + } else if (ord < maxord) { + save = FALSE; + } + } + + if (save) { + if (++T->count >= T->capacity) { + T = sf_contain(T); + Tsave = (Tsave == NULL) ? T : sf_union(Tsave, T); + T = sf_new(MAGIC, A->sf_size); + pt = T->data; + } else { + pt += T->wsize; + } + } + } + } + + + /* Contain the final result and merge it into Tsave */ + T = sf_contain(T); + Tsave = (Tsave == NULL) ? T : sf_union(Tsave, T); + + return Tsave; +} + +/* + * abs_covered -- after selecting a new column for the selected set, + * create a new matrix which is only those rows which are still uncovered + */ +static pset_family +abs_covered(A, pick) +pset_family A; +register int pick; +{ + register pset last, p, pdest; + register pset_family Aprime; + + Aprime = sf_new(A->count, A->sf_size); + pdest = Aprime->data; + foreach_set(A, last, p) + if (! is_in_set(p, pick)) { + INLINEset_copy(pdest, p); + Aprime->count++; + pdest += Aprime->wsize; + } + return Aprime; +} + + +/* + * abs_covered_many -- after selecting many columns for ther selected set, + * create a new matrix which is only those rows which are still uncovered + */ +static pset_family +abs_covered_many(A, pick_set) +pset_family A; +register pset pick_set; +{ + register pset last, p, pdest; + register pset_family Aprime; + + Aprime = sf_new(A->count, A->sf_size); + pdest = Aprime->data; + foreach_set(A, last, p) + if (setp_disjoint(p, pick_set)) { + INLINEset_copy(pdest, p); + Aprime->count++; + pdest += Aprime->wsize; + } + return Aprime; +} + + +/* + * abs_select_restricted -- select the column of maximum column count which + * also belongs to the set "restrict"; weight each column of a set as + * 1 / (set_ord(p) - 1). + */ +static int +abs_select_restricted(A, restrict) +pset_family A; +pset restrict; +{ + register int i, best_var, best_count, *count; + + /* Sum the elements in these columns */ + count = sf_count_restricted(A, restrict); + + /* Find which variable has maximum weight */ + best_var = -1; + best_count = 0; + for(i = 0; i < A->sf_size; i++) { + if (count[i] > best_count) { + best_var = i; + best_count = count[i]; + } + } + FREE(count); + + if (best_var == -1) + fatal("abs_select_restricted: should not have best_var == -1"); + + return best_var; +} diff --git a/src/misc/espresso/util_old.h b/src/misc/espresso/util_old.h new file mode 100644 index 00000000..5451cbe9 --- /dev/null +++ b/src/misc/espresso/util_old.h @@ -0,0 +1,301 @@ +/* + * Revision Control Information + * + * $Source: /vol/opua/opua2/sis/sis-1.2/common/src/sis/util/RCS/util.h,v $ + * $Author: sis $ + * $Revision: 1.9 $ + * $Date: 1993/06/07 21:04:07 $ + * + */ +#ifndef UTIL_H +#define UTIL_H + +#if defined(_IBMR2) +#ifndef _POSIX_SOURCE +#define _POSIX_SOURCE /* Argh! IBM strikes again */ +#endif +#ifndef _ALL_SOURCE +#define _ALL_SOURCE /* Argh! IBM strikes again */ +#endif +#ifndef _ANSI_C_SOURCE +#define _ANSI_C_SOURCE /* Argh! IBM strikes again */ +#endif +#endif + +#if defined(__STDC__) || defined(sprite) || defined(_IBMR2) || defined(__osf__) +#include +#endif + +#if defined(_IBMR2) && !defined(__STDC__) +#define _BSD +#endif + +#include "ansi.h" /* since some files don't include sis.h */ + +/* This was taken out and defined at compile time in the SIS Makefile + that uses the OctTools. When the OctTools are used, USE_MM is defined, + because the OctTools contain libmm.a. Otherwise, USE_MM is not defined, + since the mm package is not distributed with SIS, only with Oct. */ + +/* #define USE_MM */ /* choose libmm.a as the memory allocator */ + +#define NIL(type) ((type *) 0) + +#ifdef USE_MM +/* + * assumes the memory manager is libmm.a + * - allows malloc(0) or realloc(obj, 0) + * - catches out of memory (and calls MMout_of_memory()) + * - catch free(0) and realloc(0, size) in the macros + */ +#define ALLOC(type, num) \ + ((type *) malloc(sizeof(type) * (num))) +#define REALLOC(type, obj, num) \ + (obj) ? ((type *) realloc((char *) obj, sizeof(type) * (num))) : \ + ((type *) malloc(sizeof(type) * (num))) +#define FREE(obj) \ + ((obj) ? (free((char *) (obj)), (obj) = 0) : 0) +#else +/* + * enforce strict semantics on the memory allocator + * - when in doubt, delete the '#define USE_MM' above + */ +#define ALLOC(type, num) \ + ((type *) MMalloc((long) sizeof(type) * (long) (num))) +#define REALLOC(type, obj, num) \ + ((type *) MMrealloc((char *) (obj), (long) sizeof(type) * (long) (num))) +#define FREE(obj) \ + ((obj) ? (free((void *) (obj)), (obj) = 0) : 0) +#endif + + +/* Ultrix (and SABER) have 'fixed' certain functions which used to be int */ +#if defined(ultrix) || defined(SABER) || defined(aiws) || defined(__hpux) || defined(__STDC__) || defined(apollo) +#define VOID_HACK void +#else +#define VOID_HACK int +#endif + + +/* No machines seem to have much of a problem with these */ +#include +#include + + +/* Some machines fail to define some functions in stdio.h */ +#if !defined(__STDC__) && !defined(sprite) && !defined(_IBMR2) && !defined(__osf__) +extern FILE *popen(), *tmpfile(); +extern int pclose(); +#ifndef clearerr /* is a macro on many machines, but not all */ +extern VOID_HACK clearerr(); +#endif +#ifndef rewind +extern VOID_HACK rewind(); +#endif +#endif + +#ifndef PORT_H +#include +#include +#if defined(ultrix) +#if defined(_SIZE_T_) +#define ultrix4 +#else +#if defined(SIGLOST) +#define ultrix3 +#else +#define ultrix2 +#endif +#endif +#endif +#endif + +/* most machines don't give us a header file for these */ +#if defined(__STDC__) || defined(sprite) || defined(_IBMR2) || defined(__osf__) || defined(sunos4) || defined(__hpux) +#include +#if defined(__hpux) +#include /* For perror() defininition */ +#endif /* __hpux */ +#else +extern VOID_HACK abort(), free(), exit(), perror(); +extern char *getenv(); +#ifdef ultrix4 +extern void *malloc(), *realloc(), *calloc(); +#else +extern char *malloc(), *realloc(), *calloc(); +#endif +#if defined(aiws) +extern int sprintf(); +#else +#ifndef _IBMR2 +extern char *sprintf(); +#endif +#endif +extern int system(); +extern double atof(); +#endif + +#ifndef PORT_H +#if defined(ultrix3) || defined(sunos4) || defined(_IBMR2) || defined(__STDC__) +#define SIGNAL_FN void +#else +/* sequent, ultrix2, 4.3BSD (vax, hp), sunos3 */ +#define SIGNAL_FN int +#endif +#endif + +/* some call it strings.h, some call it string.h; others, also have memory.h */ +#if defined(__STDC__) || defined(sprite) +#include +#else +#if defined(ultrix4) || defined(__hpux) +#include +#else +#if defined(_IBMR2) || defined(__osf__) +#include +#include +#else +/* ANSI C string.h -- 1/11/88 Draft Standard */ +/* ugly, awful hack */ +#ifndef PORT_H +extern char *strcpy(), *strncpy(), *strcat(), *strncat(), *strerror(); +extern char *strpbrk(), *strtok(), *strchr(), *strrchr(), *strstr(); +extern int strcoll(), strxfrm(), strncmp(), strlen(), strspn(), strcspn(); +extern char *memmove(), *memccpy(), *memchr(), *memcpy(), *memset(); +extern int memcmp(), strcmp(); +#endif +#endif +#endif +#endif + +/* a few extras */ +#if defined(__hpux) +#define random() lrand48() +#define srandom(a) srand48(a) +#define bzero(a,b) memset(a, 0, b) +#else +#if !defined(__osf__) && !defined(linux) +/* these are defined as macros in stdlib.h */ +extern VOID_HACK srandom(); +extern long random(); +#endif +#endif + +/* code from sis-1.3 commented out below +#if defined(__STDC__) || defined(sprite) +#include +#else +#ifndef NDEBUG +#define assert(ex) {\ + if (! (ex)) {\ + (void) fprintf(stderr,\ + "Assertion failed: file %s, line %d\n\"%s\"\n",\ + __FILE__, __LINE__, "ex");\ + (void) fflush(stdout);\ + abort();\ + }\ +} +#else +#define assert(ex) {ex;} +#endif +#endif +*/ + + /* Sunil 5/3/97: + sis-1.4: dont let the assert call go to the OS, since + much of the code in SIS has actual computation done in + the assert function. %$#$@@#! The OS version of assert + will do nothing if NDEBUG is set. We cant let that happen... + */ +# ifdef NDEBUG +# define assert(ex) {ex;} +# else +# define assert(ex) {\ + if (! (ex)) {\ + (void) fprintf(stderr,\ + "Assertion failed: file %s, line %d\n\"%s\"\n",\ + __FILE__, __LINE__, "ex");\ + (void) fflush(stdout);\ + abort();\ + }\ +} +# endif + + +#define fail(why) {\ + (void) fprintf(stderr, "Fatal error: file %s, line %d\n%s\n",\ + __FILE__, __LINE__, why);\ + (void) fflush(stdout);\ + abort();\ +} + + +#ifdef lint +#undef putc /* correct lint '_flsbuf' bug */ +#undef ALLOC /* allow for lint -h flag */ +#undef REALLOC +#define ALLOC(type, num) (((type *) 0) + (num)) +#define REALLOC(type, obj, num) ((obj) + (num)) +#endif + +/* +#if !defined(__osf__) +#define MAXPATHLEN 1024 +#endif +*/ + +/* These arguably do NOT belong in util.h */ +#ifndef ABS +#define ABS(a) ((a) < 0 ? -(a) : (a)) +#endif +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + + +#ifndef USE_MM +EXTERN void MMout_of_memory ARGS((long)); +EXTERN char *MMalloc ARGS((long)); +EXTERN char *MMrealloc ARGS((char *, long)); +EXTERN void MMfree ARGS((char *)); +#endif + +EXTERN void util_print_cpu_stats ARGS((FILE *)); +EXTERN long util_cpu_time ARGS((void)); +EXTERN void util_getopt_reset ARGS((void)); +EXTERN int util_getopt ARGS((int, char **, char *)); +EXTERN char *util_path_search ARGS((char *)); +EXTERN char *util_file_search ARGS((char *, char *, char *)); +EXTERN int util_pipefork ARGS((char **, FILE **, FILE **, int *)); +EXTERN char *util_print_time ARGS((long)); +EXTERN int util_save_image ARGS((char *, char *)); +EXTERN char *util_strsav ARGS((char *)); +EXTERN int util_do_nothing ARGS((void)); +EXTERN char *util_tilde_expand ARGS((char *)); +EXTERN char *util_tempnam ARGS((char *, char *)); +EXTERN FILE *util_tmpfile ARGS((void)); +EXTERN long getSoftDataLimit(); + +#define ptime() util_cpu_time() +#define print_time(t) util_print_time(t) + +/* util_getopt() global variables (ack !) */ +extern int util_optind; +extern char *util_optarg; + +#include +#ifndef HUGE_VAL +#ifndef HUGE +#define HUGE 8.9884656743115790e+307 +#endif +#define HUGE_VAL HUGE +#endif +#ifndef MAXINT +#define MAXINT (1 << 30) +#endif + +#include +#endif diff --git a/src/misc/espresso/verify.c b/src/misc/espresso/verify.c new file mode 100644 index 00000000..64342787 --- /dev/null +++ b/src/misc/espresso/verify.c @@ -0,0 +1,193 @@ +/* + * Revision Control Information + * + * $Source$ + * $Author$ + * $Revision$ + * $Date$ + * + */ +/* + */ + +#include "espresso.h" + +/* + * verify -- check that all minterms of F are contained in (Fold u Dold) + * and that all minterms of Fold are contained in (F u Dold). + */ +bool verify(F, Fold, Dold) +pcover F, Fold, Dold; +{ + pcube p, last, *FD; + bool verify_error = FALSE; + + /* Make sure the function didn't grow too large */ + FD = cube2list(Fold, Dold); + foreach_set(F, last, p) + if (! cube_is_covered(FD, p)) { + printf("some minterm in F is not covered by Fold u Dold\n"); + verify_error = TRUE; + if (verbose_debug) printf("%s\n", pc1(p)); else break; + } + free_cubelist(FD); + + /* Make sure minimized function covers the original function */ + FD = cube2list(F, Dold); + foreach_set(Fold, last, p) + if (! cube_is_covered(FD, p)) { + printf("some minterm in Fold is not covered by F u Dold\n"); + verify_error = TRUE; + if (verbose_debug) printf("%s\n", pc1(p)); else break; + } + free_cubelist(FD); + + return verify_error; +} + + + +/* + * PLA_verify -- verify that two PLA's are identical + * + * If names are given, row and column permutations are done to make + * the comparison meaningful. + * + */ +bool PLA_verify(PLA1, PLA2) +pPLA PLA1, PLA2; +{ + /* Check if both have names given; if so, attempt to permute to + * match the names + */ + if (PLA1->label != NULL && PLA1->label[0] != NULL && + PLA2->label != NULL && PLA2->label[0] != NULL) { + PLA_permute(PLA1, PLA2); + } else { + (void) fprintf(stderr, "Warning: cannot permute columns without names\n"); + return TRUE; + } + + if (PLA1->F->sf_size != PLA2->F->sf_size) { + (void) fprintf(stderr, "PLA_verify: PLA's are not the same size\n"); + return TRUE; + } + + return verify(PLA2->F, PLA1->F, PLA1->D); +} + + + +/* + * Permute the columns of PLA1 so that they match the order of PLA2 + * Discard any columns of PLA1 which are not in PLA2 + * Association is strictly by the names of the columns of the cover. + */ +PLA_permute(PLA1, PLA2) +pPLA PLA1, PLA2; +{ + register int i, j, *permute, npermute; + register char *labi; + char **label; + + /* determine which columns of PLA1 to save, and place these in the list + * "permute"; the order in this list is the final output order + */ + npermute = 0; + permute = ALLOC(int, PLA2->F->sf_size); + for(i = 0; i < PLA2->F->sf_size; i++) { + labi = PLA2->label[i]; + for(j = 0; j < PLA1->F->sf_size; j++) { + if (strcmp(labi, PLA1->label[j]) == 0) { + permute[npermute++] = j; + break; + } + } + } + + /* permute columns */ + if (PLA1->F != NULL) { + PLA1->F = sf_permute(PLA1->F, permute, npermute); + } + if (PLA1->R != NULL) { + PLA1->R = sf_permute(PLA1->R, permute, npermute); + } + if (PLA1->D != NULL) { + PLA1->D = sf_permute(PLA1->D, permute, npermute); + } + + /* permute the labels */ + label = ALLOC(char *, cube.size); + for(i = 0; i < npermute; i++) { + label[i] = PLA1->label[permute[i]]; + } + for(i = npermute; i < cube.size; i++) { + label[i] = NULL; + } + FREE(PLA1->label); + PLA1->label = label; + + FREE(permute); +} + + + +/* + * check_consistency -- test that the ON-set, OFF-set and DC-set form + * a partition of the boolean space. + */ +bool check_consistency(PLA) +pPLA PLA; +{ + bool verify_error = FALSE; + pcover T; + + T = cv_intersect(PLA->F, PLA->D); + if (T->count == 0) + printf("ON-SET and DC-SET are disjoint\n"); + else { + printf("Some minterm(s) belong to both the ON-SET and DC-SET !\n"); + if (verbose_debug) + cprint(T); + verify_error = TRUE; + } + (void) fflush(stdout); + free_cover(T); + + T = cv_intersect(PLA->F, PLA->R); + if (T->count == 0) + printf("ON-SET and OFF-SET are disjoint\n"); + else { + printf("Some minterm(s) belong to both the ON-SET and OFF-SET !\n"); + if (verbose_debug) + cprint(T); + verify_error = TRUE; + } + (void) fflush(stdout); + free_cover(T); + + T = cv_intersect(PLA->D, PLA->R); + if (T->count == 0) + printf("DC-SET and OFF-SET are disjoint\n"); + else { + printf("Some minterm(s) belong to both the OFF-SET and DC-SET !\n"); + if (verbose_debug) + cprint(T); + verify_error = TRUE; + } + (void) fflush(stdout); + free_cover(T); + + if (tautology(cube3list(PLA->F, PLA->D, PLA->R))) + printf("Union of ON-SET, OFF-SET and DC-SET is the universe\n"); + else { + T = complement(cube3list(PLA->F, PLA->D, PLA->R)); + printf("There are minterms left unspecified !\n"); + if (verbose_debug) + cprint(T); + verify_error = TRUE; + free_cover(T); + } + (void) fflush(stdout); + return verify_error; +} diff --git a/src/misc/extra/extra.h b/src/misc/extra/extra.h new file mode 100644 index 00000000..314257a2 --- /dev/null +++ b/src/misc/extra/extra.h @@ -0,0 +1,626 @@ +/**CFile**************************************************************** + + FileName [extra.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [extra] + + Synopsis [Various reusable software utilities.] + + Description [This library contains a number of operators and + traversal routines developed to extend the functionality of + CUDD v.2.3.x, by Fabio Somenzi (http://vlsi.colorado.edu/~fabio/) + To compile your code with the library, #include "extra.h" + in your source files and link your project to CUDD and this + library. Use the library at your own risk and with caution. + Note that debugging of some operators still continues.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: extra.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#ifndef __EXTRA_H__ +#define __EXTRA_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _WIN32 +#define inline __inline // compatible with MS VS 6.0 +#endif + +/*---------------------------------------------------------------------------*/ +/* Nested includes */ +/*---------------------------------------------------------------------------*/ + +// this include should be the first one in the list +// it is used to catch memory leaks on Windows +#include "leaks.h" + +#include +#include +#include +#include +#include +#include "st.h" +#include "cuddInt.h" + +/*---------------------------------------------------------------------------*/ +/* Constant declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Stucture declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Type declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Variable declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Macro declarations */ +/*---------------------------------------------------------------------------*/ + +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint32; +#ifdef WIN32 +typedef unsigned __int64 uint64; +#else +typedef unsigned long long uint64; +#endif + +/* constants of the manager */ +#define b0 Cudd_Not((dd)->one) +#define b1 (dd)->one +#define z0 (dd)->zero +#define z1 (dd)->one +#define a0 (dd)->zero +#define a1 (dd)->one + +// hash key macros +#define hashKey1(a,TSIZE) \ +((unsigned)(a) % TSIZE) + +#define hashKey2(a,b,TSIZE) \ +(((unsigned)(a) + (unsigned)(b) * DD_P1) % TSIZE) + +#define hashKey3(a,b,c,TSIZE) \ +(((((unsigned)(a) + (unsigned)(b)) * DD_P1 + (unsigned)(c)) * DD_P2 ) % TSIZE) + +#define hashKey4(a,b,c,d,TSIZE) \ +((((((unsigned)(a) + (unsigned)(b)) * DD_P1 + (unsigned)(c)) * DD_P2 + \ + (unsigned)(d)) * DD_P3) % TSIZE) + +#define hashKey5(a,b,c,d,e,TSIZE) \ +(((((((unsigned)(a) + (unsigned)(b)) * DD_P1 + (unsigned)(c)) * DD_P2 + \ + (unsigned)(d)) * DD_P3 + (unsigned)(e)) * DD_P1) % TSIZE) + +#ifndef PRT +#define PRT(a,t) printf("%s = ", (a)); printf("%6.2f sec\n", (float)(t)/(float)(CLOCKS_PER_SEC)) +#define PRTn(a,t) printf("%s = ", (a)); printf("%6.2f sec ", (float)(t)/(float)(CLOCKS_PER_SEC)) +#endif + +#ifndef PRTP +#define PRTP(a,t,T) printf("%s = ", (a)); printf("%6.2f sec (%6.2f %%)\n", (float)(t)/(float)(CLOCKS_PER_SEC), (T)? 100.0*(t)/(T) : 0.0) +#endif + +/*===========================================================================*/ +/* Various Utilities */ +/*===========================================================================*/ + +/*=== extraBddAuto.c ========================================================*/ + +extern DdNode * Extra_bddSpaceFromFunctionFast( DdManager * dd, DdNode * bFunc ); +extern DdNode * Extra_bddSpaceFromFunction( DdManager * dd, DdNode * bF, DdNode * bG ); +extern DdNode * extraBddSpaceFromFunction( DdManager * dd, DdNode * bF, DdNode * bG ); +extern DdNode * Extra_bddSpaceFromFunctionPos( DdManager * dd, DdNode * bFunc ); +extern DdNode * extraBddSpaceFromFunctionPos( DdManager * dd, DdNode * bFunc ); +extern DdNode * Extra_bddSpaceFromFunctionNeg( DdManager * dd, DdNode * bFunc ); +extern DdNode * extraBddSpaceFromFunctionNeg( DdManager * dd, DdNode * bFunc ); + +extern DdNode * Extra_bddSpaceCanonVars( DdManager * dd, DdNode * bSpace ); +extern DdNode * extraBddSpaceCanonVars( DdManager * dd, DdNode * bSpace ); + +extern DdNode * Extra_bddSpaceEquations( DdManager * dd, DdNode * bSpace ); +extern DdNode * Extra_bddSpaceEquationsNeg( DdManager * dd, DdNode * bSpace ); +extern DdNode * extraBddSpaceEquationsNeg( DdManager * dd, DdNode * bSpace ); +extern DdNode * Extra_bddSpaceEquationsPos( DdManager * dd, DdNode * bSpace ); +extern DdNode * extraBddSpaceEquationsPos( DdManager * dd, DdNode * bSpace ); + +extern DdNode * Extra_bddSpaceFromMatrixPos( DdManager * dd, DdNode * zA ); +extern DdNode * extraBddSpaceFromMatrixPos( DdManager * dd, DdNode * zA ); +extern DdNode * Extra_bddSpaceFromMatrixNeg( DdManager * dd, DdNode * zA ); +extern DdNode * extraBddSpaceFromMatrixNeg( DdManager * dd, DdNode * zA ); + +extern DdNode * Extra_bddSpaceReduce( DdManager * dd, DdNode * bFunc, DdNode * bCanonVars ); +extern DdNode ** Extra_bddSpaceExorGates( DdManager * dd, DdNode * bFuncRed, DdNode * zEquations ); + +/*=== extraBddCas.c =============================================================*/ + +/* performs the binary encoding of the set of function using the given vars */ +extern DdNode * Extra_bddEncodingBinary( DdManager * dd, DdNode ** pbFuncs, int nFuncs, DdNode ** pbVars, int nVars ); +/* solves the column encoding problem using a sophisticated method */ +extern DdNode * Extra_bddEncodingNonStrict( DdManager * dd, DdNode ** pbColumns, int nColumns, DdNode * bVarsCol, DdNode ** pCVars, int nMulti, int * pSimple ); +/* collects the nodes under the cut and, for each node, computes the sum of paths leading to it from the root */ +extern st_table * Extra_bddNodePathsUnderCut( DdManager * dd, DdNode * bFunc, int CutLevel ); +/* collects the nodes under the cut starting from the given set of ADD nodes */ +extern int Extra_bddNodePathsUnderCutArray( DdManager * dd, DdNode ** paNodes, DdNode ** pbCubes, int nNodes, DdNode ** paNodesRes, DdNode ** pbCubesRes, int CutLevel ); +/* find the profile of a DD (the number of edges crossing each level) */ +extern int Extra_ProfileWidth( DdManager * dd, DdNode * F, int * Profile, int CutLevel ); + +/*=== extraBddMisc.c ========================================================*/ + +extern DdNode * Extra_TransferPermute( DdManager * ddSource, DdManager * ddDestination, DdNode * f, int * Permute ); +extern DdNode * Extra_TransferLevelByLevel( DdManager * ddSource, DdManager * ddDestination, DdNode * f ); +extern DdNode * Extra_bddRemapUp( DdManager * dd, DdNode * bF ); +extern DdNode * Extra_bddMove( DdManager * dd, DdNode * bF, int fShiftUp ); +extern DdNode * extraBddMove( DdManager * dd, DdNode * bF, DdNode * bFlag ); +extern void Extra_StopManager( DdManager * dd ); +extern void Extra_bddPrint( DdManager * dd, DdNode * F ); +extern void extraDecomposeCover( DdManager* dd, DdNode* zC, DdNode** zC0, DdNode** zC1, DdNode** zC2 ); +extern int Extra_bddSuppSize( DdManager * dd, DdNode * bSupp ); +extern int Extra_bddSuppContainVar( DdManager * dd, DdNode * bS, DdNode * bVar ); +extern int Extra_bddSuppOverlapping( DdManager * dd, DdNode * S1, DdNode * S2 ); +extern int Extra_bddSuppDifferentVars( DdManager * dd, DdNode * S1, DdNode * S2, int DiffMax ); +extern int Extra_bddSuppCheckContainment( DdManager * dd, DdNode * bL, DdNode * bH, DdNode ** bLarge, DdNode ** bSmall ); +extern int * Extra_SupportArray( DdManager * dd, DdNode * F, int * support ); +extern int * Extra_VectorSupportArray( DdManager * dd, DdNode ** F, int n, int * support ); +extern DdNode * Extra_bddFindOneCube( DdManager * dd, DdNode * bF ); +extern DdNode * Extra_bddGetOneCube( DdManager * dd, DdNode * bFunc ); +extern DdNode * Extra_bddComputeRangeCube( DdManager * dd, int iStart, int iStop ); +extern DdNode * Extra_bddBitsToCube( DdManager * dd, int Code, int CodeWidth, DdNode ** pbVars, int fMsbFirst ); +extern DdNode * Extra_bddSupportNegativeCube( DdManager * dd, DdNode * f ); +extern int Extra_bddIsVar( DdNode * bFunc ); +extern DdNode * Extra_bddCreateAnd( DdManager * dd, int nVars ); +extern DdNode * Extra_bddCreateOr( DdManager * dd, int nVars ); +extern DdNode * Extra_bddCreateExor( DdManager * dd, int nVars ); +extern DdNode * Extra_zddPrimes( DdManager * dd, DdNode * F ); +extern void Extra_bddPermuteArray( DdManager * dd, DdNode ** bNodesIn, DdNode ** bNodesOut, int nNodes, int *permut ); + +/*=== extraBddKmap.c ================================================================*/ + +/* displays the Karnaugh Map of a function */ +extern void Extra_PrintKMap( FILE * pFile, DdManager * dd, DdNode * OnSet, DdNode * OffSet, int nVars, DdNode ** XVars, int fSuppType, char ** pVarNames ); +/* displays the Karnaugh Map of a relation */ +extern void Extra_PrintKMapRelation( FILE * pFile, DdManager * dd, DdNode * OnSet, DdNode * OffSet, int nXVars, int nYVars, DdNode ** XVars, DdNode ** YVars ); + +/*=== extraBddSymm.c =================================================================*/ + +typedef struct Extra_SymmInfo_t_ Extra_SymmInfo_t; +struct Extra_SymmInfo_t_ { + int nVars; // the number of variables in the support + int nVarsMax; // the number of variables in the DD manager + int nSymms; // the number of pair-wise symmetries + int nNodes; // the number of nodes in a ZDD (if applicable) + int * pVars; // the list of all variables present in the support + char ** pSymms; // the symmetry information +}; + +/* computes the classical symmetry information for the function - recursive */ +extern Extra_SymmInfo_t * Extra_SymmPairsCompute( DdManager * dd, DdNode * bFunc ); +/* computes the classical symmetry information for the function - using naive approach */ +extern Extra_SymmInfo_t * Extra_SymmPairsComputeNaive( DdManager * dd, DdNode * bFunc ); +extern int Extra_bddCheckVarsSymmetricNaive( DdManager * dd, DdNode * bF, int iVar1, int iVar2 ); + +/* allocates the data structure */ +extern Extra_SymmInfo_t * Extra_SymmPairsAllocate( int nVars ); +/* deallocates the data structure */ +extern void Extra_SymmPairsDissolve( Extra_SymmInfo_t * ); +/* print the contents the data structure */ +extern void Extra_SymmPairsPrint( Extra_SymmInfo_t * ); +/* converts the ZDD into the Extra_SymmInfo_t structure */ +extern Extra_SymmInfo_t * Extra_SymmPairsCreateFromZdd( DdManager * dd, DdNode * zPairs, DdNode * bVars ); + +/* computes the classical symmetry information as a ZDD */ +extern DdNode * Extra_zddSymmPairsCompute( DdManager * dd, DdNode * bF, DdNode * bVars ); +extern DdNode * extraZddSymmPairsCompute( DdManager * dd, DdNode * bF, DdNode * bVars ); +/* returns a singleton-set ZDD containing all variables that are symmetric with the given one */ +extern DdNode * Extra_zddGetSymmetricVars( DdManager * dd, DdNode * bF, DdNode * bG, DdNode * bVars ); +extern DdNode * extraZddGetSymmetricVars( DdManager * dd, DdNode * bF, DdNode * bG, DdNode * bVars ); +/* converts a set of variables into a set of singleton subsets */ +extern DdNode * Extra_zddGetSingletons( DdManager * dd, DdNode * bVars ); +extern DdNode * extraZddGetSingletons( DdManager * dd, DdNode * bVars ); +/* filters the set of variables using the support of the function */ +extern DdNode * Extra_bddReduceVarSet( DdManager * dd, DdNode * bVars, DdNode * bF ); +extern DdNode * extraBddReduceVarSet( DdManager * dd, DdNode * bVars, DdNode * bF ); + +/* checks the possibility that the two vars are symmetric */ +extern int Extra_bddCheckVarsSymmetric( DdManager * dd, DdNode * bF, int iVar1, int iVar2 ); +extern DdNode * extraBddCheckVarsSymmetric( DdManager * dd, DdNode * bF, DdNode * bVars ); + +/* build the set of all tuples of K variables out of N from the BDD cube */ +extern DdNode * Extra_zddTuplesFromBdd( DdManager * dd, int K, DdNode * bVarsN ); +extern DdNode * extraZddTuplesFromBdd( DdManager * dd, DdNode * bVarsK, DdNode * bVarsN ); +/* selects one subset from a ZDD representing the set of subsets */ +extern DdNode * Extra_zddSelectOneSubset( DdManager * dd, DdNode * zS ); +extern DdNode * extraZddSelectOneSubset( DdManager * dd, DdNode * zS ); + +/*=== extraBddUnate.c =================================================================*/ + +typedef struct Extra_UnateVar_t_ Extra_UnateVar_t; +struct Extra_UnateVar_t_ { + unsigned iVar : 30; // index of the variable + unsigned Pos : 1; // 1 if positive unate + unsigned Neg : 1; // 1 if negative unate +}; + +typedef struct Extra_UnateInfo_t_ Extra_UnateInfo_t; +struct Extra_UnateInfo_t_ { + int nVars; // the number of variables in the support + int nVarsMax; // the number of variables in the DD manager + int nUnate; // the number of unate variables + Extra_UnateVar_t * pVars; // the array of variables present in the support +}; + +/* allocates the data structure */ +extern Extra_UnateInfo_t * Extra_UnateInfoAllocate( int nVars ); +/* deallocates the data structure */ +extern void Extra_UnateInfoDissolve( Extra_UnateInfo_t * ); +/* print the contents the data structure */ +extern void Extra_UnateInfoPrint( Extra_UnateInfo_t * ); +/* converts the ZDD into the Extra_SymmInfo_t structure */ +extern Extra_UnateInfo_t * Extra_UnateInfoCreateFromZdd( DdManager * dd, DdNode * zUnate, DdNode * bVars ); +/* naive check of unateness of one variable */ +extern int Extra_bddCheckUnateNaive( DdManager * dd, DdNode * bF, int iVar ); + +/* computes the unateness information for the function */ +extern Extra_UnateInfo_t * Extra_UnateComputeFast( DdManager * dd, DdNode * bFunc ); +extern Extra_UnateInfo_t * Extra_UnateComputeSlow( DdManager * dd, DdNode * bFunc ); + +/* computes the classical symmetry information as a ZDD */ +extern DdNode * Extra_zddUnateInfoCompute( DdManager * dd, DdNode * bF, DdNode * bVars ); +extern DdNode * extraZddUnateInfoCompute( DdManager * dd, DdNode * bF, DdNode * bVars ); + +/* converts a set of variables into a set of singleton subsets */ +extern DdNode * Extra_zddGetSingletonsBoth( DdManager * dd, DdNode * bVars ); +extern DdNode * extraZddGetSingletonsBoth( DdManager * dd, DdNode * bVars ); + +/*=== extraUtilBitMatrix.c ================================================================*/ + +typedef struct Extra_BitMat_t_ Extra_BitMat_t; +extern Extra_BitMat_t * Extra_BitMatrixStart( int nSize ); +extern void Extra_BitMatrixClean( Extra_BitMat_t * p ); +extern void Extra_BitMatrixStop( Extra_BitMat_t * p ); +extern void Extra_BitMatrixPrint( Extra_BitMat_t * p ); +extern int Extra_BitMatrixReadSize( Extra_BitMat_t * p ); +extern void Extra_BitMatrixInsert1( Extra_BitMat_t * p, int i, int k ); +extern int Extra_BitMatrixLookup1( Extra_BitMat_t * p, int i, int k ); +extern void Extra_BitMatrixDelete1( Extra_BitMat_t * p, int i, int k ); +extern void Extra_BitMatrixInsert2( Extra_BitMat_t * p, int i, int k ); +extern int Extra_BitMatrixLookup2( Extra_BitMat_t * p, int i, int k ); +extern void Extra_BitMatrixDelete2( Extra_BitMat_t * p, int i, int k ); +extern void Extra_BitMatrixOr( Extra_BitMat_t * p, int i, unsigned * pInfo ); +extern void Extra_BitMatrixOrTwo( Extra_BitMat_t * p, int i, int j ); +extern int Extra_BitMatrixCountOnesUpper( Extra_BitMat_t * p ); +extern int Extra_BitMatrixIsDisjoint( Extra_BitMat_t * p1, Extra_BitMat_t * p2 ); +extern int Extra_BitMatrixIsClique( Extra_BitMat_t * p ); + +/*=== extraUtilFile.c ========================================================*/ + +extern char * Extra_FileGetSimilarName( char * pFileNameWrong, char * pS1, char * pS2, char * pS3, char * pS4, char * pS5 ); +extern char * Extra_FileNameExtension( char * FileName ); +extern char * Extra_FileNameAppend( char * pBase, char * pSuffix ); +extern char * Extra_FileNameGeneric( char * FileName ); +extern int Extra_FileSize( char * pFileName ); +extern char * Extra_FileRead( FILE * pFile ); +extern char * Extra_TimeStamp(); +extern char * Extra_StringAppend( char * pStrGiven, char * pStrAdd ); +extern unsigned Extra_ReadBinary( char * Buffer ); +extern void Extra_PrintBinary( FILE * pFile, unsigned Sign[], int nBits ); +extern int Extra_ReadHexadecimal( unsigned Sign[], char * pString, int nVars ); +extern void Extra_PrintHexadecimal( FILE * pFile, unsigned Sign[], int nVars ); +extern void Extra_PrintHexadecimalString( char * pString, unsigned Sign[], int nVars ); +extern void Extra_PrintHex( FILE * pFile, unsigned uTruth, int nVars ); +extern void Extra_PrintSymbols( FILE * pFile, char Char, int nTimes, int fPrintNewLine ); + +/*=== extraUtilReader.c ========================================================*/ + +typedef struct Extra_FileReader_t_ Extra_FileReader_t; +extern Extra_FileReader_t * Extra_FileReaderAlloc( char * pFileName, + char * pCharsComment, char * pCharsStop, char * pCharsClean ); +extern void Extra_FileReaderFree( Extra_FileReader_t * p ); +extern char * Extra_FileReaderGetFileName( Extra_FileReader_t * p ); +extern int Extra_FileReaderGetFileSize( Extra_FileReader_t * p ); +extern int Extra_FileReaderGetCurPosition( Extra_FileReader_t * p ); +extern void * Extra_FileReaderGetTokens( Extra_FileReader_t * p ); +extern int Extra_FileReaderGetLineNumber( Extra_FileReader_t * p, int iToken ); + +/*=== extraUtilMemory.c ========================================================*/ + +typedef struct Extra_MmFixed_t_ Extra_MmFixed_t; +typedef struct Extra_MmFlex_t_ Extra_MmFlex_t; +typedef struct Extra_MmStep_t_ Extra_MmStep_t; + +// fixed-size-block memory manager +extern Extra_MmFixed_t * Extra_MmFixedStart( int nEntrySize ); +extern void Extra_MmFixedStop( Extra_MmFixed_t * p ); +extern char * Extra_MmFixedEntryFetch( Extra_MmFixed_t * p ); +extern void Extra_MmFixedEntryRecycle( Extra_MmFixed_t * p, char * pEntry ); +extern void Extra_MmFixedRestart( Extra_MmFixed_t * p ); +extern int Extra_MmFixedReadMemUsage( Extra_MmFixed_t * p ); +extern int Extra_MmFixedReadMaxEntriesUsed( Extra_MmFixed_t * p ); +// flexible-size-block memory manager +extern Extra_MmFlex_t * Extra_MmFlexStart(); +extern void Extra_MmFlexStop( Extra_MmFlex_t * p ); +extern void Extra_MmFlexPrint( Extra_MmFlex_t * p ); +extern char * Extra_MmFlexEntryFetch( Extra_MmFlex_t * p, int nBytes ); +extern int Extra_MmFlexReadMemUsage( Extra_MmFlex_t * p ); +// hierarchical memory manager +extern Extra_MmStep_t * Extra_MmStepStart( int nSteps ); +extern void Extra_MmStepStop( Extra_MmStep_t * p ); +extern char * Extra_MmStepEntryFetch( Extra_MmStep_t * p, int nBytes ); +extern void Extra_MmStepEntryRecycle( Extra_MmStep_t * p, char * pEntry, int nBytes ); +extern int Extra_MmStepReadMemUsage( Extra_MmStep_t * p ); + +/*=== extraUtilMisc.c ========================================================*/ + +/* finds the smallest integer larger or equal than the logarithm */ +extern int Extra_Base2Log( unsigned Num ); +extern int Extra_Base2LogDouble( double Num ); +extern int Extra_Base10Log( unsigned Num ); +/* returns the power of two as a double */ +extern double Extra_Power2( int Num ); +extern int Extra_Power3( int Num ); +/* the number of combinations of k elements out of n */ +extern int Extra_NumCombinations( int k, int n ); +extern int * Extra_DeriveRadixCode( int Number, int Radix, int nDigits ); +/* counts the number of 1s in the bitstring */ +extern int Extra_CountOnes( unsigned char * pBytes, int nBytes ); +/* the factorial of number */ +extern int Extra_Factorial( int n ); +/* the permutation of the given number of elements */ +extern char ** Extra_Permutations( int n ); +/* permutation and complementation of a truth table */ +unsigned Extra_TruthPermute( unsigned Truth, char * pPerms, int nVars, int fReverse ); +unsigned Extra_TruthPolarize( unsigned uTruth, int Polarity, int nVars ); +/* canonical forms of a truth table */ +extern unsigned Extra_TruthCanonN( unsigned uTruth, int nVars ); +extern unsigned Extra_TruthCanonNN( unsigned uTruth, int nVars ); +extern unsigned Extra_TruthCanonP( unsigned uTruth, int nVars ); +extern unsigned Extra_TruthCanonNP( unsigned uTruth, int nVars ); +extern unsigned Extra_TruthCanonNPN( unsigned uTruth, int nVars ); +/* canonical forms of 4-variable functions */ +extern void Extra_Truth4VarNPN( unsigned short ** puCanons, char ** puPhases, char ** puPerms, unsigned char ** puMap ); +extern void Extra_Truth4VarN( unsigned short ** puCanons, char *** puPhases, char ** ppCounters, int nPhasesMax ); +/* permutation mapping */ +extern unsigned short Extra_TruthPerm4One( unsigned uTruth, int Phase ); +extern unsigned Extra_TruthPerm5One( unsigned uTruth, int Phase ); +extern void Extra_TruthPerm6One( unsigned * uTruth, int Phase, unsigned * uTruthRes ); +extern void Extra_TruthExpand( int nVars, int nWords, unsigned * puTruth, unsigned uPhase, unsigned * puTruthR ); +/* precomputing tables for permutation mapping */ +extern void ** Extra_ArrayAlloc( int nCols, int nRows, int Size ); +extern unsigned short ** Extra_TruthPerm43(); +extern unsigned ** Extra_TruthPerm53(); +extern unsigned ** Extra_TruthPerm54(); +/* bubble sort for small number of entries */ +extern void Extra_BubbleSort( int Order[], int Costs[], int nSize, int fIncreasing ); +/* for independence from CUDD */ +extern unsigned int Cudd_PrimeCopy( unsigned int p ); + +/*=== extraUtilCanon.c ========================================================*/ + +/* fast computation of N-canoninical form up to 6 inputs */ +extern int Extra_TruthCanonFastN( int nVarsMax, int nVarsReal, unsigned * pt, unsigned ** pptRes, char ** ppfRes ); + +/*=== extraUtilProgress.c ================================================================*/ + +typedef struct ProgressBarStruct ProgressBar; + +extern ProgressBar * Extra_ProgressBarStart( FILE * pFile, int nItemsTotal ); +extern void Extra_ProgressBarStop( ProgressBar * p ); +extern void Extra_ProgressBarUpdate_int( ProgressBar * p, int nItemsCur, char * pString ); + +static inline void Extra_ProgressBarUpdate( ProgressBar * p, int nItemsCur, char * pString ) +{ if ( p && nItemsCur < *((int*)p) ) return; Extra_ProgressBarUpdate_int(p, nItemsCur, pString); } + +/*=== extraUtilTruth.c ================================================================*/ + +static inline int Extra_Float2Int( float Val ) { return *((int *)&Val); } +static inline float Extra_Int2Float( int Num ) { return *((float *)&Num); } +static inline int Extra_BitWordNum( int nBits ) { return nBits/(8*sizeof(unsigned)) + ((nBits%(8*sizeof(unsigned))) > 0); } +static inline int Extra_TruthWordNum( int nVars ) { return nVars <= 5 ? 1 : (1 << (nVars - 5)); } + +static inline void Extra_TruthSetBit( unsigned * p, int Bit ) { p[Bit>>5] |= (1<<(Bit & 31)); } +static inline void Extra_TruthXorBit( unsigned * p, int Bit ) { p[Bit>>5] ^= (1<<(Bit & 31)); } +static inline int Extra_TruthHasBit( unsigned * p, int Bit ) { return (p[Bit>>5] & (1<<(Bit & 31))) > 0; } + +static inline int Extra_WordCountOnes( unsigned uWord ) +{ + uWord = (uWord & 0x55555555) + ((uWord>>1) & 0x55555555); + uWord = (uWord & 0x33333333) + ((uWord>>2) & 0x33333333); + uWord = (uWord & 0x0F0F0F0F) + ((uWord>>4) & 0x0F0F0F0F); + uWord = (uWord & 0x00FF00FF) + ((uWord>>8) & 0x00FF00FF); + return (uWord & 0x0000FFFF) + (uWord>>16); +} +static inline int Extra_TruthCountOnes( unsigned * pIn, int nVars ) +{ + int w, Counter = 0; + for ( w = Extra_TruthWordNum(nVars)-1; w >= 0; w-- ) + Counter += Extra_WordCountOnes(pIn[w]); + return Counter; +} +static inline int Extra_TruthIsEqual( unsigned * pIn0, unsigned * pIn1, int nVars ) +{ + int w; + for ( w = Extra_TruthWordNum(nVars)-1; w >= 0; w-- ) + if ( pIn0[w] != pIn1[w] ) + return 0; + return 1; +} +static inline int Extra_TruthIsConst0( unsigned * pIn, int nVars ) +{ + int w; + for ( w = Extra_TruthWordNum(nVars)-1; w >= 0; w-- ) + if ( pIn[w] ) + return 0; + return 1; +} +static inline int Extra_TruthIsConst1( unsigned * pIn, int nVars ) +{ + int w; + for ( w = Extra_TruthWordNum(nVars)-1; w >= 0; w-- ) + if ( pIn[w] != ~(unsigned)0 ) + return 0; + return 1; +} +static inline int Extra_TruthIsImply( unsigned * pIn1, unsigned * pIn2, int nVars ) +{ + int w; + for ( w = Extra_TruthWordNum(nVars)-1; w >= 0; w-- ) + if ( pIn1[w] & ~pIn2[w] ) + return 0; + return 1; +} +static inline void Extra_TruthCopy( unsigned * pOut, unsigned * pIn, int nVars ) +{ + int w; + for ( w = Extra_TruthWordNum(nVars)-1; w >= 0; w-- ) + pOut[w] = pIn[w]; +} +static inline void Extra_TruthClear( unsigned * pOut, int nVars ) +{ + int w; + for ( w = Extra_TruthWordNum(nVars)-1; w >= 0; w-- ) + pOut[w] = 0; +} +static inline void Extra_TruthFill( unsigned * pOut, int nVars ) +{ + int w; + for ( w = Extra_TruthWordNum(nVars)-1; w >= 0; w-- ) + pOut[w] = ~(unsigned)0; +} +static inline void Extra_TruthNot( unsigned * pOut, unsigned * pIn, int nVars ) +{ + int w; + for ( w = Extra_TruthWordNum(nVars)-1; w >= 0; w-- ) + pOut[w] = ~pIn[w]; +} +static inline void Extra_TruthAnd( unsigned * pOut, unsigned * pIn0, unsigned * pIn1, int nVars ) +{ + int w; + for ( w = Extra_TruthWordNum(nVars)-1; w >= 0; w-- ) + pOut[w] = pIn0[w] & pIn1[w]; +} +static inline void Extra_TruthOr( unsigned * pOut, unsigned * pIn0, unsigned * pIn1, int nVars ) +{ + int w; + for ( w = Extra_TruthWordNum(nVars)-1; w >= 0; w-- ) + pOut[w] = pIn0[w] | pIn1[w]; +} +static inline void Extra_TruthSharp( unsigned * pOut, unsigned * pIn0, unsigned * pIn1, int nVars ) +{ + int w; + for ( w = Extra_TruthWordNum(nVars)-1; w >= 0; w-- ) + pOut[w] = pIn0[w] & ~pIn1[w]; +} +static inline void Extra_TruthNand( unsigned * pOut, unsigned * pIn0, unsigned * pIn1, int nVars ) +{ + int w; + for ( w = Extra_TruthWordNum(nVars)-1; w >= 0; w-- ) + pOut[w] = ~(pIn0[w] & pIn1[w]); +} +static inline void Extra_TruthAndPhase( unsigned * pOut, unsigned * pIn0, unsigned * pIn1, int nVars, int fCompl0, int fCompl1 ) +{ + int w; + if ( fCompl0 && fCompl1 ) + { + for ( w = Extra_TruthWordNum(nVars)-1; w >= 0; w-- ) + pOut[w] = ~(pIn0[w] | pIn1[w]); + } + else if ( fCompl0 && !fCompl1 ) + { + for ( w = Extra_TruthWordNum(nVars)-1; w >= 0; w-- ) + pOut[w] = ~pIn0[w] & pIn1[w]; + } + else if ( !fCompl0 && fCompl1 ) + { + for ( w = Extra_TruthWordNum(nVars)-1; w >= 0; w-- ) + pOut[w] = pIn0[w] & ~pIn1[w]; + } + else // if ( !fCompl0 && !fCompl1 ) + { + for ( w = Extra_TruthWordNum(nVars)-1; w >= 0; w-- ) + pOut[w] = pIn0[w] & pIn1[w]; + } +} + +extern unsigned ** Extra_TruthElementary( int nVars ); +extern void Extra_TruthSwapAdjacentVars( unsigned * pOut, unsigned * pIn, int nVars, int Start ); +extern void Extra_TruthStretch( unsigned * pOut, unsigned * pIn, int nVars, int nVarsAll, unsigned Phase ); +extern void Extra_TruthShrink( unsigned * pOut, unsigned * pIn, int nVars, int nVarsAll, unsigned Phase ); +extern int Extra_TruthVarInSupport( unsigned * pTruth, int nVars, int iVar ); +extern int Extra_TruthSupportSize( unsigned * pTruth, int nVars ); +extern int Extra_TruthSupport( unsigned * pTruth, int nVars ); +extern void Extra_TruthCofactor0( unsigned * pTruth, int nVars, int iVar ); +extern void Extra_TruthCofactor1( unsigned * pTruth, int nVars, int iVar ); +extern void Extra_TruthExist( unsigned * pTruth, int nVars, int iVar ); +extern void Extra_TruthForall( unsigned * pTruth, int nVars, int iVar ); +extern void Extra_TruthMux( unsigned * pOut, unsigned * pCof0, unsigned * pCof1, int nVars, int iVar ); +extern void Extra_TruthChangePhase( unsigned * pTruth, int nVars, int iVar ); +extern int Extra_TruthMinCofSuppOverlap( unsigned * pTruth, int nVars, int * pVarMin ); +extern void Extra_TruthCountOnesInCofs( unsigned * pTruth, int nVars, short * pStore ); +extern unsigned Extra_TruthHash( unsigned * pIn, int nWords ); +extern unsigned Extra_TruthSemiCanonicize( unsigned * pInOut, unsigned * pAux, int nVars, char * pCanonPerm, short * pStore ); + +/*=== extraUtilUtil.c ================================================================*/ + +#ifndef ABS +#define ABS(a) ((a) < 0 ? -(a) : (a)) +#endif + +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef ALLOC +#define ALLOC(type, num) ((type *) malloc(sizeof(type) * (num))) +#endif + +#ifndef FREE +#define FREE(obj) ((obj) ? (free((char *) (obj)), (obj) = 0) : 0) +#endif + +#ifndef REALLOC +#define REALLOC(type, obj, num) \ + ((obj) ? ((type *) realloc((char *)(obj), sizeof(type) * (num))) : \ + ((type *) malloc(sizeof(type) * (num)))) +#endif + + +extern long Extra_CpuTime(); +extern int Extra_GetSoftDataLimit(); +extern void Extra_UtilGetoptReset(); +extern int Extra_UtilGetopt( int argc, char *argv[], char *optstring ); +extern char * Extra_UtilPrintTime( long t ); +extern char * Extra_UtilStrsav( char *s ); +extern char * Extra_UtilTildeExpand( char *fname ); +extern char * Extra_UtilFileSearch( char *file, char *path, char *mode ); +extern void (*Extra_UtilMMoutOfMemory)(); + +extern char * globalUtilOptarg; +extern int globalUtilOptind; + +/**AutomaticEnd***************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* __EXTRA_H__ */ diff --git a/src/misc/extra/extraBddAuto.c b/src/misc/extra/extraBddAuto.c new file mode 100644 index 00000000..21a969ba --- /dev/null +++ b/src/misc/extra/extraBddAuto.c @@ -0,0 +1,1558 @@ +/**CFile**************************************************************** + + FileName [extraBddAuto.c] + + PackageName [extra] + + Synopsis [Computation of autosymmetries.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 2.0. Started - September 1, 2003.] + + Revision [$Id: extraBddAuto.c,v 1.0 2003/05/21 18:03:50 alanmi Exp $] + +***********************************************************************/ + +#include "extra.h" + +/*---------------------------------------------------------------------------*/ +/* Constant declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Stucture declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Type declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Variable declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Macro declarations */ +/*---------------------------------------------------------------------------*/ + + +/**AutomaticStart*************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Static function prototypes */ +/*---------------------------------------------------------------------------*/ + +/**AutomaticEnd***************************************************************/ + + +/* + LinearSpace(f) = Space(f,f) + + Space(f,g) + { + if ( f = const ) + { + if ( f = g ) return 1; + else return 0; + } + if ( g = const ) return 0; + return x' * Space(fx',gx') * Space(fx,gx) + x * Space(fx',gx) * Space(fx,gx'); + } + + Equations(s) = Pos(s) + Neg(s); + + Pos(s) + { + if ( s = 0 ) return 1; + if ( s = 1 ) return 0; + if ( sx'= 0 ) return Pos(sx) + x; + if ( sx = 0 ) return Pos(sx'); + return 1 * [Pos(sx') & Pos(sx)] + x * [Pos(sx') & Neg(sx)]; + } + + Neg(s) + { + if ( s = 0 ) return 1; + if ( s = 1 ) return 0; + if ( sx'= 0 ) return Neg(sx); + if ( sx = 0 ) return Neg(sx') + x; + return 1 * [Neg(sx') & Neg(sx)] + x * [Neg(sx') & Pos(sx)]; + } + + + SpaceP(A) + { + if ( A = 0 ) return 1; + if ( A = 1 ) return 1; + return x' * SpaceP(Ax') * SpaceP(Ax) + x * SpaceP(Ax') * SpaceN(Ax); + } + + SpaceN(A) + { + if ( A = 0 ) return 1; + if ( A = 1 ) return 0; + return x' * SpaceN(Ax') * SpaceN(Ax) + x * SpaceN(Ax') * SpaceP(Ax); + } + + + LinInd(A) + { + if ( A = const ) return 1; + if ( !LinInd(Ax') ) return 0; + if ( !LinInd(Ax) ) return 0; + if ( LinSumOdd(Ax') & LinSumEven(Ax) != 0 ) return 0; + if ( LinSumEven(Ax') & LinSumEven(Ax) != 0 ) return 0; + return 1; + } + + LinSumOdd(A) + { + if ( A = 0 ) return 0; // Odd0 ---e-- Odd1 + if ( A = 1 ) return 1; // \ o + Odd0 = LinSumOdd(Ax'); // x is absent // \ + Even0 = LinSumEven(Ax'); // x is absent // / o + Odd1 = LinSumOdd(Ax); // x is present // Even0 ---e-- Even1 + Even1 = LinSumEven(Ax); // x is absent + return 1 * [Odd0 + ExorP(Odd0, Even1)] + x * [Odd1 + ExorP(Odd1, Even0)]; + } + + LinSumEven(A) + { + if ( A = 0 ) return 0; + if ( A = 1 ) return 0; + Odd0 = LinSumOdd(Ax'); // x is absent + Even0 = LinSumEven(Ax'); // x is absent + Odd1 = LinSumOdd(Ax); // x is present + Even1 = LinSumEven(Ax); // x is absent + return 1 * [Even0 + Even1 + ExorP(Even0, Even1)] + x * [ExorP(Odd0, Odd1)]; + } + +*/ + +/*---------------------------------------------------------------------------*/ +/* Definition of exported functions */ +/*---------------------------------------------------------------------------*/ + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Extra_bddSpaceFromFunctionFast( DdManager * dd, DdNode * bFunc ) +{ + int * pSupport; + int * pPermute; + int * pPermuteBack; + DdNode ** pCompose; + DdNode * bCube, * bTemp; + DdNode * bSpace, * bFunc1, * bFunc2, * bSpaceShift; + int nSupp, Counter; + int i, lev; + + // get the support + pSupport = ALLOC( int, ddMax(dd->size,dd->sizeZ) ); + Extra_SupportArray( dd, bFunc, pSupport ); + nSupp = 0; + for ( i = 0; i < dd->size; i++ ) + if ( pSupport[i] ) + nSupp++; + + // make sure the manager has enough variables + if ( 2*nSupp > dd->size ) + { + printf( "Cannot derive linear space, because DD manager does not have enough variables.\n" ); + fflush( stdout ); + free( pSupport ); + return NULL; + } + + // create the permutation arrays + pPermute = ALLOC( int, dd->size ); + pPermuteBack = ALLOC( int, dd->size ); + pCompose = ALLOC( DdNode *, dd->size ); + for ( i = 0; i < dd->size; i++ ) + { + pPermute[i] = i; + pPermuteBack[i] = i; + pCompose[i] = dd->vars[i]; Cudd_Ref( pCompose[i] ); + } + + // remap the function in such a way that the variables are interleaved + Counter = 0; + bCube = b1; Cudd_Ref( bCube ); + for ( lev = 0; lev < dd->size; lev++ ) + if ( pSupport[ dd->invperm[lev] ] ) + { // var "dd->invperm[lev]" on level "lev" should go to level 2*Counter; + pPermute[ dd->invperm[lev] ] = dd->invperm[2*Counter]; + // var from level 2*Counter+1 should go back to the place of this var + pPermuteBack[ dd->invperm[2*Counter+1] ] = dd->invperm[lev]; + // the permutation should be defined in such a way that variable + // on level 2*Counter is replaced by an EXOR of itself and var on the next level + Cudd_Deref( pCompose[ dd->invperm[2*Counter] ] ); + pCompose[ dd->invperm[2*Counter] ] = + Cudd_bddXor( dd, dd->vars[ dd->invperm[2*Counter] ], dd->vars[ dd->invperm[2*Counter+1] ] ); + Cudd_Ref( pCompose[ dd->invperm[2*Counter] ] ); + // add this variable to the cube + bCube = Cudd_bddAnd( dd, bTemp = bCube, dd->vars[ dd->invperm[2*Counter] ] ); Cudd_Ref( bCube ); + Cudd_RecursiveDeref( dd, bTemp ); + // increment the counter + Counter ++; + } + + // permute the functions + bFunc1 = Cudd_bddPermute( dd, bFunc, pPermute ); Cudd_Ref( bFunc1 ); + // compose to gate the function depending on both vars + bFunc2 = Cudd_bddVectorCompose( dd, bFunc1, pCompose ); Cudd_Ref( bFunc2 ); + // gate the vector space + // L(a) = ForAll x [ F(x) = F(x+a) ] = Not( Exist x [ F(x) (+) F(x+a) ] ) + bSpaceShift = Cudd_bddXorExistAbstract( dd, bFunc1, bFunc2, bCube ); Cudd_Ref( bSpaceShift ); + bSpaceShift = Cudd_Not( bSpaceShift ); + // permute the space back into the original mapping + bSpace = Cudd_bddPermute( dd, bSpaceShift, pPermuteBack ); Cudd_Ref( bSpace ); + Cudd_RecursiveDeref( dd, bFunc1 ); + Cudd_RecursiveDeref( dd, bFunc2 ); + Cudd_RecursiveDeref( dd, bSpaceShift ); + Cudd_RecursiveDeref( dd, bCube ); + + for ( i = 0; i < dd->size; i++ ) + Cudd_RecursiveDeref( dd, pCompose[i] ); + free( pPermute ); + free( pPermuteBack ); + free( pCompose ); + free( pSupport ); + + Cudd_Deref( bSpace ); + return bSpace; +} + + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Extra_bddSpaceFromFunction( DdManager * dd, DdNode * bF, DdNode * bG ) +{ + DdNode * bRes; + do { + dd->reordered = 0; + bRes = extraBddSpaceFromFunction( dd, bF, bG ); + } while (dd->reordered == 1); + return bRes; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Extra_bddSpaceFromFunctionPos( DdManager * dd, DdNode * bFunc ) +{ + DdNode * bRes; + do { + dd->reordered = 0; + bRes = extraBddSpaceFromFunctionPos( dd, bFunc ); + } while (dd->reordered == 1); + return bRes; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Extra_bddSpaceFromFunctionNeg( DdManager * dd, DdNode * bFunc ) +{ + DdNode * bRes; + do { + dd->reordered = 0; + bRes = extraBddSpaceFromFunctionNeg( dd, bFunc ); + } while (dd->reordered == 1); + return bRes; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Extra_bddSpaceCanonVars( DdManager * dd, DdNode * bSpace ) +{ + DdNode * bRes; + do { + dd->reordered = 0; + bRes = extraBddSpaceCanonVars( dd, bSpace ); + } while (dd->reordered == 1); + return bRes; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Extra_bddSpaceReduce( DdManager * dd, DdNode * bFunc, DdNode * bCanonVars ) +{ + DdNode * bNegCube; + DdNode * bResult; + bNegCube = Extra_bddSupportNegativeCube( dd, bCanonVars ); Cudd_Ref( bNegCube ); + bResult = Cudd_Cofactor( dd, bFunc, bNegCube ); Cudd_Ref( bResult ); + Cudd_RecursiveDeref( dd, bNegCube ); + Cudd_Deref( bResult ); + return bResult; +} + + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Extra_bddSpaceEquations( DdManager * dd, DdNode * bSpace ) +{ + DdNode * zRes; + DdNode * zEquPos; + DdNode * zEquNeg; + zEquPos = Extra_bddSpaceEquationsPos( dd, bSpace ); Cudd_Ref( zEquPos ); + zEquNeg = Extra_bddSpaceEquationsNeg( dd, bSpace ); Cudd_Ref( zEquNeg ); + zRes = Cudd_zddUnion( dd, zEquPos, zEquNeg ); Cudd_Ref( zRes ); + Cudd_RecursiveDerefZdd( dd, zEquPos ); + Cudd_RecursiveDerefZdd( dd, zEquNeg ); + Cudd_Deref( zRes ); + return zRes; +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Extra_bddSpaceEquationsPos( DdManager * dd, DdNode * bSpace ) +{ + DdNode * zRes; + do { + dd->reordered = 0; + zRes = extraBddSpaceEquationsPos( dd, bSpace ); + } while (dd->reordered == 1); + return zRes; +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Extra_bddSpaceEquationsNeg( DdManager * dd, DdNode * bSpace ) +{ + DdNode * zRes; + do { + dd->reordered = 0; + zRes = extraBddSpaceEquationsNeg( dd, bSpace ); + } while (dd->reordered == 1); + return zRes; +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Extra_bddSpaceFromMatrixPos( DdManager * dd, DdNode * zA ) +{ + DdNode * bRes; + do { + dd->reordered = 0; + bRes = extraBddSpaceFromMatrixPos( dd, zA ); + } while (dd->reordered == 1); + return bRes; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Extra_bddSpaceFromMatrixNeg( DdManager * dd, DdNode * zA ) +{ + DdNode * bRes; + do { + dd->reordered = 0; + bRes = extraBddSpaceFromMatrixNeg( dd, zA ); + } while (dd->reordered == 1); + return bRes; +} + +/**Function************************************************************* + + Synopsis [Counts the number of literals in one combination.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Extra_zddLitCountComb( DdManager * dd, DdNode * zComb ) +{ + int Counter; + if ( zComb == z0 ) + return 0; + Counter = 0; + for ( ; zComb != z1; zComb = cuddT(zComb) ) + Counter++; + return Counter; +} + +/**Function************************************************************* + + Synopsis [] + + Description [Returns the array of ZDDs with the number equal to the number of + vars in the DD manager. If the given var is non-canonical, this array contains + the referenced ZDD representing literals in the corresponding EXOR equation.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode ** Extra_bddSpaceExorGates( DdManager * dd, DdNode * bFuncRed, DdNode * zEquations ) +{ + DdNode ** pzRes; + int * pVarsNonCan; + DdNode * zEquRem; + int iVarNonCan; + DdNode * zExor, * zTemp; + + // get the set of non-canonical variables + pVarsNonCan = ALLOC( int, ddMax(dd->size,dd->sizeZ) ); + Extra_SupportArray( dd, bFuncRed, pVarsNonCan ); + + // allocate storage for the EXOR sets + pzRes = ALLOC( DdNode *, dd->size ); + memset( pzRes, 0, sizeof(DdNode *) * dd->size ); + + // go through all the equations + zEquRem = zEquations; Cudd_Ref( zEquRem ); + while ( zEquRem != z0 ) + { + // extract one product + zExor = Extra_zddSelectOneSubset( dd, zEquRem ); Cudd_Ref( zExor ); + // remove it from the set + zEquRem = Cudd_zddDiff( dd, zTemp = zEquRem, zExor ); Cudd_Ref( zEquRem ); + Cudd_RecursiveDerefZdd( dd, zTemp ); + + // locate the non-canonical variable + iVarNonCan = -1; + for ( zTemp = zExor; zTemp != z1; zTemp = cuddT(zTemp) ) + { + if ( pVarsNonCan[zTemp->index/2] == 1 ) + { + assert( iVarNonCan == -1 ); + iVarNonCan = zTemp->index/2; + } + } + assert( iVarNonCan != -1 ); + + if ( Extra_zddLitCountComb( dd, zExor ) > 1 ) + pzRes[ iVarNonCan ] = zExor; // takes ref + else + Cudd_RecursiveDerefZdd( dd, zExor ); + } + Cudd_RecursiveDerefZdd( dd, zEquRem ); + + free( pVarsNonCan ); + return pzRes; +} + + +/*---------------------------------------------------------------------------*/ +/* Definition of internal functions */ +/*---------------------------------------------------------------------------*/ + +/**Function******************************************************************** + + Synopsis [Performs the recursive steps of Extra_bddSpaceFromFunction.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * extraBddSpaceFromFunction( DdManager * dd, DdNode * bF, DdNode * bG ) +{ + DdNode * bRes; + DdNode * bFR, * bGR; + + bFR = Cudd_Regular( bF ); + bGR = Cudd_Regular( bG ); + if ( cuddIsConstant(bFR) ) + { + if ( bF == bG ) + return b1; + else + return b0; + } + if ( cuddIsConstant(bGR) ) + return b0; + // both bFunc and bCore are not constants + + // the operation is commutative - normalize the problem + if ( (unsigned)bF > (unsigned)bG ) + return extraBddSpaceFromFunction(dd, bG, bF); + + + if ( bRes = cuddCacheLookup2(dd, extraBddSpaceFromFunction, bF, bG) ) + return bRes; + else + { + DdNode * bF0, * bF1; + DdNode * bG0, * bG1; + DdNode * bTemp1, * bTemp2; + DdNode * bRes0, * bRes1; + int LevelF, LevelG; + int index; + + LevelF = dd->perm[bFR->index]; + LevelG = dd->perm[bGR->index]; + if ( LevelF <= LevelG ) + { + index = dd->invperm[LevelF]; + if ( bFR != bF ) + { + bF0 = Cudd_Not( cuddE(bFR) ); + bF1 = Cudd_Not( cuddT(bFR) ); + } + else + { + bF0 = cuddE(bFR); + bF1 = cuddT(bFR); + } + } + else + { + index = dd->invperm[LevelG]; + bF0 = bF1 = bF; + } + + if ( LevelG <= LevelF ) + { + if ( bGR != bG ) + { + bG0 = Cudd_Not( cuddE(bGR) ); + bG1 = Cudd_Not( cuddT(bGR) ); + } + else + { + bG0 = cuddE(bGR); + bG1 = cuddT(bGR); + } + } + else + bG0 = bG1 = bG; + + bTemp1 = extraBddSpaceFromFunction( dd, bF0, bG0 ); + if ( bTemp1 == NULL ) + return NULL; + cuddRef( bTemp1 ); + + bTemp2 = extraBddSpaceFromFunction( dd, bF1, bG1 ); + if ( bTemp2 == NULL ) + { + Cudd_RecursiveDeref( dd, bTemp1 ); + return NULL; + } + cuddRef( bTemp2 ); + + + bRes0 = cuddBddAndRecur( dd, bTemp1, bTemp2 ); + if ( bRes0 == NULL ) + { + Cudd_RecursiveDeref( dd, bTemp1 ); + Cudd_RecursiveDeref( dd, bTemp2 ); + return NULL; + } + cuddRef( bRes0 ); + Cudd_RecursiveDeref( dd, bTemp1 ); + Cudd_RecursiveDeref( dd, bTemp2 ); + + + bTemp1 = extraBddSpaceFromFunction( dd, bF0, bG1 ); + if ( bTemp1 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + return NULL; + } + cuddRef( bTemp1 ); + + bTemp2 = extraBddSpaceFromFunction( dd, bF1, bG0 ); + if ( bTemp2 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + Cudd_RecursiveDeref( dd, bTemp1 ); + return NULL; + } + cuddRef( bTemp2 ); + + bRes1 = cuddBddAndRecur( dd, bTemp1, bTemp2 ); + if ( bRes1 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + Cudd_RecursiveDeref( dd, bTemp1 ); + Cudd_RecursiveDeref( dd, bTemp2 ); + return NULL; + } + cuddRef( bRes1 ); + Cudd_RecursiveDeref( dd, bTemp1 ); + Cudd_RecursiveDeref( dd, bTemp2 ); + + + + // consider the case when Res0 and Res1 are the same node + if ( bRes0 == bRes1 ) + bRes = bRes1; + // consider the case when Res1 is complemented + else if ( Cudd_IsComplement(bRes1) ) + { + bRes = cuddUniqueInter(dd, index, Cudd_Not(bRes1), Cudd_Not(bRes0)); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref(dd,bRes0); + Cudd_RecursiveDeref(dd,bRes1); + return NULL; + } + bRes = Cudd_Not(bRes); + } + else + { + bRes = cuddUniqueInter( dd, index, bRes1, bRes0 ); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref(dd,bRes0); + Cudd_RecursiveDeref(dd,bRes1); + return NULL; + } + } + cuddDeref( bRes0 ); + cuddDeref( bRes1 ); + + // insert the result into cache + cuddCacheInsert2(dd, extraBddSpaceFromFunction, bF, bG, bRes); + return bRes; + } +} /* end of extraBddSpaceFromFunction */ + + + +/**Function************************************************************* + + Synopsis [Performs the recursive step of Extra_bddSpaceFromFunctionPos().] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * extraBddSpaceFromFunctionPos( DdManager * dd, DdNode * bF ) +{ + DdNode * bRes, * bFR; + statLine( dd ); + + bFR = Cudd_Regular(bF); + if ( cuddIsConstant(bFR) ) + return b1; + + if ( bRes = cuddCacheLookup1(dd, extraBddSpaceFromFunctionPos, bF) ) + return bRes; + else + { + DdNode * bF0, * bF1; + DdNode * bPos0, * bPos1; + DdNode * bNeg0, * bNeg1; + DdNode * bRes0, * bRes1; + + if ( bFR != bF ) // bF is complemented + { + bF0 = Cudd_Not( cuddE(bFR) ); + bF1 = Cudd_Not( cuddT(bFR) ); + } + else + { + bF0 = cuddE(bFR); + bF1 = cuddT(bFR); + } + + + bPos0 = extraBddSpaceFromFunctionPos( dd, bF0 ); + if ( bPos0 == NULL ) + return NULL; + cuddRef( bPos0 ); + + bPos1 = extraBddSpaceFromFunctionPos( dd, bF1 ); + if ( bPos1 == NULL ) + { + Cudd_RecursiveDeref( dd, bPos0 ); + return NULL; + } + cuddRef( bPos1 ); + + bRes0 = cuddBddAndRecur( dd, bPos0, bPos1 ); + if ( bRes0 == NULL ) + { + Cudd_RecursiveDeref( dd, bPos0 ); + Cudd_RecursiveDeref( dd, bPos1 ); + return NULL; + } + cuddRef( bRes0 ); + Cudd_RecursiveDeref( dd, bPos0 ); + Cudd_RecursiveDeref( dd, bPos1 ); + + + bNeg0 = extraBddSpaceFromFunctionNeg( dd, bF0 ); + if ( bNeg0 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + return NULL; + } + cuddRef( bNeg0 ); + + bNeg1 = extraBddSpaceFromFunctionNeg( dd, bF1 ); + if ( bNeg1 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + Cudd_RecursiveDeref( dd, bNeg0 ); + return NULL; + } + cuddRef( bNeg1 ); + + bRes1 = cuddBddAndRecur( dd, bNeg0, bNeg1 ); + if ( bRes1 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + Cudd_RecursiveDeref( dd, bNeg0 ); + Cudd_RecursiveDeref( dd, bNeg1 ); + return NULL; + } + cuddRef( bRes1 ); + Cudd_RecursiveDeref( dd, bNeg0 ); + Cudd_RecursiveDeref( dd, bNeg1 ); + + + // consider the case when Res0 and Res1 are the same node + if ( bRes0 == bRes1 ) + bRes = bRes1; + // consider the case when Res1 is complemented + else if ( Cudd_IsComplement(bRes1) ) + { + bRes = cuddUniqueInter( dd, bFR->index, Cudd_Not(bRes1), Cudd_Not(bRes0) ); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref(dd,bRes0); + Cudd_RecursiveDeref(dd,bRes1); + return NULL; + } + bRes = Cudd_Not(bRes); + } + else + { + bRes = cuddUniqueInter( dd, bFR->index, bRes1, bRes0 ); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref(dd,bRes0); + Cudd_RecursiveDeref(dd,bRes1); + return NULL; + } + } + cuddDeref( bRes0 ); + cuddDeref( bRes1 ); + + cuddCacheInsert1( dd, extraBddSpaceFromFunctionPos, bF, bRes ); + return bRes; + } +} + + + +/**Function************************************************************* + + Synopsis [Performs the recursive step of Extra_bddSpaceFromFunctionPos().] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * extraBddSpaceFromFunctionNeg( DdManager * dd, DdNode * bF ) +{ + DdNode * bRes, * bFR; + statLine( dd ); + + bFR = Cudd_Regular(bF); + if ( cuddIsConstant(bFR) ) + return b0; + + if ( bRes = cuddCacheLookup1(dd, extraBddSpaceFromFunctionNeg, bF) ) + return bRes; + else + { + DdNode * bF0, * bF1; + DdNode * bPos0, * bPos1; + DdNode * bNeg0, * bNeg1; + DdNode * bRes0, * bRes1; + + if ( bFR != bF ) // bF is complemented + { + bF0 = Cudd_Not( cuddE(bFR) ); + bF1 = Cudd_Not( cuddT(bFR) ); + } + else + { + bF0 = cuddE(bFR); + bF1 = cuddT(bFR); + } + + + bPos0 = extraBddSpaceFromFunctionNeg( dd, bF0 ); + if ( bPos0 == NULL ) + return NULL; + cuddRef( bPos0 ); + + bPos1 = extraBddSpaceFromFunctionNeg( dd, bF1 ); + if ( bPos1 == NULL ) + { + Cudd_RecursiveDeref( dd, bPos0 ); + return NULL; + } + cuddRef( bPos1 ); + + bRes0 = cuddBddAndRecur( dd, bPos0, bPos1 ); + if ( bRes0 == NULL ) + { + Cudd_RecursiveDeref( dd, bPos0 ); + Cudd_RecursiveDeref( dd, bPos1 ); + return NULL; + } + cuddRef( bRes0 ); + Cudd_RecursiveDeref( dd, bPos0 ); + Cudd_RecursiveDeref( dd, bPos1 ); + + + bNeg0 = extraBddSpaceFromFunctionPos( dd, bF0 ); + if ( bNeg0 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + return NULL; + } + cuddRef( bNeg0 ); + + bNeg1 = extraBddSpaceFromFunctionPos( dd, bF1 ); + if ( bNeg1 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + Cudd_RecursiveDeref( dd, bNeg0 ); + return NULL; + } + cuddRef( bNeg1 ); + + bRes1 = cuddBddAndRecur( dd, bNeg0, bNeg1 ); + if ( bRes1 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + Cudd_RecursiveDeref( dd, bNeg0 ); + Cudd_RecursiveDeref( dd, bNeg1 ); + return NULL; + } + cuddRef( bRes1 ); + Cudd_RecursiveDeref( dd, bNeg0 ); + Cudd_RecursiveDeref( dd, bNeg1 ); + + + // consider the case when Res0 and Res1 are the same node + if ( bRes0 == bRes1 ) + bRes = bRes1; + // consider the case when Res1 is complemented + else if ( Cudd_IsComplement(bRes1) ) + { + bRes = cuddUniqueInter( dd, bFR->index, Cudd_Not(bRes1), Cudd_Not(bRes0) ); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref(dd,bRes0); + Cudd_RecursiveDeref(dd,bRes1); + return NULL; + } + bRes = Cudd_Not(bRes); + } + else + { + bRes = cuddUniqueInter( dd, bFR->index, bRes1, bRes0 ); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref(dd,bRes0); + Cudd_RecursiveDeref(dd,bRes1); + return NULL; + } + } + cuddDeref( bRes0 ); + cuddDeref( bRes1 ); + + cuddCacheInsert1( dd, extraBddSpaceFromFunctionNeg, bF, bRes ); + return bRes; + } +} + + + +/**Function************************************************************* + + Synopsis [Performs the recursive step of Extra_bddSpaceCanonVars().] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * extraBddSpaceCanonVars( DdManager * dd, DdNode * bF ) +{ + DdNode * bRes, * bFR; + statLine( dd ); + + bFR = Cudd_Regular(bF); + if ( cuddIsConstant(bFR) ) + return bF; + + if ( bRes = cuddCacheLookup1(dd, extraBddSpaceCanonVars, bF) ) + return bRes; + else + { + DdNode * bF0, * bF1; + DdNode * bRes, * bRes0; + + if ( bFR != bF ) // bF is complemented + { + bF0 = Cudd_Not( cuddE(bFR) ); + bF1 = Cudd_Not( cuddT(bFR) ); + } + else + { + bF0 = cuddE(bFR); + bF1 = cuddT(bFR); + } + + if ( bF0 == b0 ) + { + bRes = extraBddSpaceCanonVars( dd, bF1 ); + if ( bRes == NULL ) + return NULL; + } + else if ( bF1 == b0 ) + { + bRes = extraBddSpaceCanonVars( dd, bF0 ); + if ( bRes == NULL ) + return NULL; + } + else + { + bRes0 = extraBddSpaceCanonVars( dd, bF0 ); + if ( bRes0 == NULL ) + return NULL; + cuddRef( bRes0 ); + + bRes = cuddUniqueInter( dd, bFR->index, bRes0, b0 ); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref( dd,bRes0 ); + return NULL; + } + cuddDeref( bRes0 ); + } + + cuddCacheInsert1( dd, extraBddSpaceCanonVars, bF, bRes ); + return bRes; + } +} + +/**Function************************************************************* + + Synopsis [Performs the recursive step of Extra_bddSpaceEquationsPos().] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * extraBddSpaceEquationsPos( DdManager * dd, DdNode * bF ) +{ + DdNode * zRes; + statLine( dd ); + + if ( bF == b0 ) + return z1; + if ( bF == b1 ) + return z0; + + if ( zRes = cuddCacheLookup1Zdd(dd, extraBddSpaceEquationsPos, bF) ) + return zRes; + else + { + DdNode * bFR, * bF0, * bF1; + DdNode * zPos0, * zPos1, * zNeg1; + DdNode * zRes, * zRes0, * zRes1; + + bFR = Cudd_Regular(bF); + if ( bFR != bF ) // bF is complemented + { + bF0 = Cudd_Not( cuddE(bFR) ); + bF1 = Cudd_Not( cuddT(bFR) ); + } + else + { + bF0 = cuddE(bFR); + bF1 = cuddT(bFR); + } + + if ( bF0 == b0 ) + { + zRes1 = extraBddSpaceEquationsPos( dd, bF1 ); + if ( zRes1 == NULL ) + return NULL; + cuddRef( zRes1 ); + + // add the current element to the set + zRes = cuddZddGetNode( dd, 2*bFR->index, z1, zRes1 ); + if ( zRes == NULL ) + { + Cudd_RecursiveDerefZdd(dd, zRes1); + return NULL; + } + cuddDeref( zRes1 ); + } + else if ( bF1 == b0 ) + { + zRes = extraBddSpaceEquationsPos( dd, bF0 ); + if ( zRes == NULL ) + return NULL; + } + else + { + zPos0 = extraBddSpaceEquationsPos( dd, bF0 ); + if ( zPos0 == NULL ) + return NULL; + cuddRef( zPos0 ); + + zPos1 = extraBddSpaceEquationsPos( dd, bF1 ); + if ( zPos1 == NULL ) + { + Cudd_RecursiveDerefZdd(dd, zPos0); + return NULL; + } + cuddRef( zPos1 ); + + zNeg1 = extraBddSpaceEquationsNeg( dd, bF1 ); + if ( zNeg1 == NULL ) + { + Cudd_RecursiveDerefZdd(dd, zPos0); + Cudd_RecursiveDerefZdd(dd, zPos1); + return NULL; + } + cuddRef( zNeg1 ); + + + zRes0 = cuddZddIntersect( dd, zPos0, zPos1 ); + if ( zRes0 == NULL ) + { + Cudd_RecursiveDerefZdd(dd, zNeg1); + Cudd_RecursiveDerefZdd(dd, zPos0); + Cudd_RecursiveDerefZdd(dd, zPos1); + return NULL; + } + cuddRef( zRes0 ); + + zRes1 = cuddZddIntersect( dd, zPos0, zNeg1 ); + if ( zRes1 == NULL ) + { + Cudd_RecursiveDerefZdd(dd, zRes0); + Cudd_RecursiveDerefZdd(dd, zNeg1); + Cudd_RecursiveDerefZdd(dd, zPos0); + Cudd_RecursiveDerefZdd(dd, zPos1); + return NULL; + } + cuddRef( zRes1 ); + Cudd_RecursiveDerefZdd(dd, zNeg1); + Cudd_RecursiveDerefZdd(dd, zPos0); + Cudd_RecursiveDerefZdd(dd, zPos1); + // only zRes0 and zRes1 are refed at this point + + zRes = cuddZddGetNode( dd, 2*bFR->index, zRes1, zRes0 ); + if ( zRes == NULL ) + { + Cudd_RecursiveDerefZdd(dd, zRes0); + Cudd_RecursiveDerefZdd(dd, zRes1); + return NULL; + } + cuddDeref( zRes0 ); + cuddDeref( zRes1 ); + } + + cuddCacheInsert1( dd, extraBddSpaceEquationsPos, bF, zRes ); + return zRes; + } +} + + +/**Function************************************************************* + + Synopsis [Performs the recursive step of Extra_bddSpaceEquationsNev().] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * extraBddSpaceEquationsNeg( DdManager * dd, DdNode * bF ) +{ + DdNode * zRes; + statLine( dd ); + + if ( bF == b0 ) + return z1; + if ( bF == b1 ) + return z0; + + if ( zRes = cuddCacheLookup1Zdd(dd, extraBddSpaceEquationsNeg, bF) ) + return zRes; + else + { + DdNode * bFR, * bF0, * bF1; + DdNode * zPos0, * zPos1, * zNeg1; + DdNode * zRes, * zRes0, * zRes1; + + bFR = Cudd_Regular(bF); + if ( bFR != bF ) // bF is complemented + { + bF0 = Cudd_Not( cuddE(bFR) ); + bF1 = Cudd_Not( cuddT(bFR) ); + } + else + { + bF0 = cuddE(bFR); + bF1 = cuddT(bFR); + } + + if ( bF0 == b0 ) + { + zRes = extraBddSpaceEquationsNeg( dd, bF1 ); + if ( zRes == NULL ) + return NULL; + } + else if ( bF1 == b0 ) + { + zRes0 = extraBddSpaceEquationsNeg( dd, bF0 ); + if ( zRes0 == NULL ) + return NULL; + cuddRef( zRes0 ); + + // add the current element to the set + zRes = cuddZddGetNode( dd, 2*bFR->index, z1, zRes0 ); + if ( zRes == NULL ) + { + Cudd_RecursiveDerefZdd(dd, zRes0); + return NULL; + } + cuddDeref( zRes0 ); + } + else + { + zPos0 = extraBddSpaceEquationsNeg( dd, bF0 ); + if ( zPos0 == NULL ) + return NULL; + cuddRef( zPos0 ); + + zPos1 = extraBddSpaceEquationsNeg( dd, bF1 ); + if ( zPos1 == NULL ) + { + Cudd_RecursiveDerefZdd(dd, zPos0); + return NULL; + } + cuddRef( zPos1 ); + + zNeg1 = extraBddSpaceEquationsPos( dd, bF1 ); + if ( zNeg1 == NULL ) + { + Cudd_RecursiveDerefZdd(dd, zPos0); + Cudd_RecursiveDerefZdd(dd, zPos1); + return NULL; + } + cuddRef( zNeg1 ); + + + zRes0 = cuddZddIntersect( dd, zPos0, zPos1 ); + if ( zRes0 == NULL ) + { + Cudd_RecursiveDerefZdd(dd, zNeg1); + Cudd_RecursiveDerefZdd(dd, zPos0); + Cudd_RecursiveDerefZdd(dd, zPos1); + return NULL; + } + cuddRef( zRes0 ); + + zRes1 = cuddZddIntersect( dd, zPos0, zNeg1 ); + if ( zRes1 == NULL ) + { + Cudd_RecursiveDerefZdd(dd, zRes0); + Cudd_RecursiveDerefZdd(dd, zNeg1); + Cudd_RecursiveDerefZdd(dd, zPos0); + Cudd_RecursiveDerefZdd(dd, zPos1); + return NULL; + } + cuddRef( zRes1 ); + Cudd_RecursiveDerefZdd(dd, zNeg1); + Cudd_RecursiveDerefZdd(dd, zPos0); + Cudd_RecursiveDerefZdd(dd, zPos1); + // only zRes0 and zRes1 are refed at this point + + zRes = cuddZddGetNode( dd, 2*bFR->index, zRes1, zRes0 ); + if ( zRes == NULL ) + { + Cudd_RecursiveDerefZdd(dd, zRes0); + Cudd_RecursiveDerefZdd(dd, zRes1); + return NULL; + } + cuddDeref( zRes0 ); + cuddDeref( zRes1 ); + } + + cuddCacheInsert1( dd, extraBddSpaceEquationsNeg, bF, zRes ); + return zRes; + } +} + + + + +/**Function************************************************************* + + Synopsis [Performs the recursive step of Extra_bddSpaceFromFunctionPos().] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * extraBddSpaceFromMatrixPos( DdManager * dd, DdNode * zA ) +{ + DdNode * bRes; + statLine( dd ); + + if ( zA == z0 ) + return b1; + if ( zA == z1 ) + return b1; + + if ( bRes = cuddCacheLookup1(dd, extraBddSpaceFromMatrixPos, zA) ) + return bRes; + else + { + DdNode * bP0, * bP1; + DdNode * bN0, * bN1; + DdNode * bRes0, * bRes1; + + bP0 = extraBddSpaceFromMatrixPos( dd, cuddE(zA) ); + if ( bP0 == NULL ) + return NULL; + cuddRef( bP0 ); + + bP1 = extraBddSpaceFromMatrixPos( dd, cuddT(zA) ); + if ( bP1 == NULL ) + { + Cudd_RecursiveDeref( dd, bP0 ); + return NULL; + } + cuddRef( bP1 ); + + bRes0 = cuddBddAndRecur( dd, bP0, bP1 ); + if ( bRes0 == NULL ) + { + Cudd_RecursiveDeref( dd, bP0 ); + Cudd_RecursiveDeref( dd, bP1 ); + return NULL; + } + cuddRef( bRes0 ); + Cudd_RecursiveDeref( dd, bP0 ); + Cudd_RecursiveDeref( dd, bP1 ); + + + bN0 = extraBddSpaceFromMatrixPos( dd, cuddE(zA) ); + if ( bN0 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + return NULL; + } + cuddRef( bN0 ); + + bN1 = extraBddSpaceFromMatrixNeg( dd, cuddT(zA) ); + if ( bN1 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + Cudd_RecursiveDeref( dd, bN0 ); + return NULL; + } + cuddRef( bN1 ); + + bRes1 = cuddBddAndRecur( dd, bN0, bN1 ); + if ( bRes1 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + Cudd_RecursiveDeref( dd, bN0 ); + Cudd_RecursiveDeref( dd, bN1 ); + return NULL; + } + cuddRef( bRes1 ); + Cudd_RecursiveDeref( dd, bN0 ); + Cudd_RecursiveDeref( dd, bN1 ); + + + // consider the case when Res0 and Res1 are the same node + if ( bRes0 == bRes1 ) + bRes = bRes1; + // consider the case when Res1 is complemented + else if ( Cudd_IsComplement(bRes1) ) + { + bRes = cuddUniqueInter( dd, zA->index/2, Cudd_Not(bRes1), Cudd_Not(bRes0) ); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref(dd,bRes0); + Cudd_RecursiveDeref(dd,bRes1); + return NULL; + } + bRes = Cudd_Not(bRes); + } + else + { + bRes = cuddUniqueInter( dd, zA->index/2, bRes1, bRes0 ); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref(dd,bRes0); + Cudd_RecursiveDeref(dd,bRes1); + return NULL; + } + } + cuddDeref( bRes0 ); + cuddDeref( bRes1 ); + + cuddCacheInsert1( dd, extraBddSpaceFromMatrixPos, zA, bRes ); + return bRes; + } +} + + +/**Function************************************************************* + + Synopsis [Performs the recursive step of Extra_bddSpaceFromFunctionPos().] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * extraBddSpaceFromMatrixNeg( DdManager * dd, DdNode * zA ) +{ + DdNode * bRes; + statLine( dd ); + + if ( zA == z0 ) + return b1; + if ( zA == z1 ) + return b0; + + if ( bRes = cuddCacheLookup1(dd, extraBddSpaceFromMatrixNeg, zA) ) + return bRes; + else + { + DdNode * bP0, * bP1; + DdNode * bN0, * bN1; + DdNode * bRes0, * bRes1; + + bP0 = extraBddSpaceFromMatrixNeg( dd, cuddE(zA) ); + if ( bP0 == NULL ) + return NULL; + cuddRef( bP0 ); + + bP1 = extraBddSpaceFromMatrixNeg( dd, cuddT(zA) ); + if ( bP1 == NULL ) + { + Cudd_RecursiveDeref( dd, bP0 ); + return NULL; + } + cuddRef( bP1 ); + + bRes0 = cuddBddAndRecur( dd, bP0, bP1 ); + if ( bRes0 == NULL ) + { + Cudd_RecursiveDeref( dd, bP0 ); + Cudd_RecursiveDeref( dd, bP1 ); + return NULL; + } + cuddRef( bRes0 ); + Cudd_RecursiveDeref( dd, bP0 ); + Cudd_RecursiveDeref( dd, bP1 ); + + + bN0 = extraBddSpaceFromMatrixNeg( dd, cuddE(zA) ); + if ( bN0 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + return NULL; + } + cuddRef( bN0 ); + + bN1 = extraBddSpaceFromMatrixPos( dd, cuddT(zA) ); + if ( bN1 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + Cudd_RecursiveDeref( dd, bN0 ); + return NULL; + } + cuddRef( bN1 ); + + bRes1 = cuddBddAndRecur( dd, bN0, bN1 ); + if ( bRes1 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + Cudd_RecursiveDeref( dd, bN0 ); + Cudd_RecursiveDeref( dd, bN1 ); + return NULL; + } + cuddRef( bRes1 ); + Cudd_RecursiveDeref( dd, bN0 ); + Cudd_RecursiveDeref( dd, bN1 ); + + + // consider the case when Res0 and Res1 are the same node + if ( bRes0 == bRes1 ) + bRes = bRes1; + // consider the case when Res1 is complemented + else if ( Cudd_IsComplement(bRes1) ) + { + bRes = cuddUniqueInter( dd, zA->index/2, Cudd_Not(bRes1), Cudd_Not(bRes0) ); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref(dd,bRes0); + Cudd_RecursiveDeref(dd,bRes1); + return NULL; + } + bRes = Cudd_Not(bRes); + } + else + { + bRes = cuddUniqueInter( dd, zA->index/2, bRes1, bRes0 ); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref(dd,bRes0); + Cudd_RecursiveDeref(dd,bRes1); + return NULL; + } + } + cuddDeref( bRes0 ); + cuddDeref( bRes1 ); + + cuddCacheInsert1( dd, extraBddSpaceFromMatrixNeg, zA, bRes ); + return bRes; + } +} + + +/*---------------------------------------------------------------------------*/ +/* Definition of static functions */ +/*---------------------------------------------------------------------------*/ + diff --git a/src/misc/extra/extraBddCas.c b/src/misc/extra/extraBddCas.c new file mode 100644 index 00000000..29382bfb --- /dev/null +++ b/src/misc/extra/extraBddCas.c @@ -0,0 +1,1230 @@ +/**CFile**************************************************************** + + FileName [extraBddCas.c] + + PackageName [extra] + + Synopsis [Procedures related to LUT cascade synthesis.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 2.0. Started - September 1, 2003.] + + Revision [$Id: extraBddCas.c,v 1.0 2003/05/21 18:03:50 alanmi Exp $] + +***********************************************************************/ + +#include "extra.h" + +/*---------------------------------------------------------------------------*/ +/* Constant declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Stucture declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Type declarations */ +/*---------------------------------------------------------------------------*/ + +// the table to store cofactor operations +#define _TABLESIZE_COF 51113 +typedef struct +{ + unsigned Sign; + DdNode * Arg1; +} _HashEntry_cof; +_HashEntry_cof HHTable1[_TABLESIZE_COF]; + +// the table to store the result of computation of the number of minterms +#define _TABLESIZE_MINT 15113 +typedef struct +{ + DdNode * Arg1; + unsigned Arg2; + unsigned Res; +} _HashEntry_mint; +_HashEntry_mint HHTable2[_TABLESIZE_MINT]; + +typedef struct +{ + int nEdges; // the number of in-coming edges of the node + DdNode * bSum; // the sum of paths of the incoming edges +} traventry; + +// the signature used for hashing +static unsigned s_Signature = 1; + +static int s_CutLevel = 0; + +/*---------------------------------------------------------------------------*/ +/* Variable declarations */ +/*---------------------------------------------------------------------------*/ + +// because the proposed solution to the optimal encoding problem has exponential complexity +// we limit the depth of the branch and bound procedure to 5 levels +static int s_MaxDepth = 5; + +static int s_nVarsBest; // the number of vars in the best ordering +static int s_VarOrderBest[32]; // storing the best ordering of vars in the "simple encoding" +static int s_VarOrderCur[32]; // storing the current ordering of vars + +// the place to store the supports of the encoded function +static DdNode * s_Field[8][256]; // the size should be K, 2^K, where K is no less than MaxDepth +static DdNode * s_Encoded; // this is the original function +static DdNode * s_VarAll; // the set of all column variables +static int s_MultiStart; // the total number of encoding variables used +// the array field now stores the supports + +static DdNode ** s_pbTemp; // the temporary storage for the columns + +static int s_BackTracks; +static int s_BackTrackLimit = 100; + +static DdNode * s_Terminal; // the terminal value for counting minterms + + +static int s_EncodingVarsLevel; + + +/*---------------------------------------------------------------------------*/ +/* Macro declarations */ +/*---------------------------------------------------------------------------*/ + + +/**AutomaticStart*************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Static function prototypes */ +/*---------------------------------------------------------------------------*/ + +static DdNode * CreateTheCodes_rec( DdManager * dd, DdNode * bEncoded, int Level, DdNode ** pCVars ); +static void EvaluateEncodings_rec( DdManager * dd, DdNode * bVarsCol, int nVarsCol, int nMulti, int Level ); +// functions called from EvaluateEncodings_rec() +static DdNode * ComputeVarSetAndCountMinterms( DdManager * dd, DdNode * bVars, DdNode * bVarTop, unsigned * Cost ); +static DdNode * ComputeVarSetAndCountMinterms2( DdManager * dd, DdNode * bVars, DdNode * bVarTop, unsigned * Cost ); +unsigned Extra_CountCofactorMinterms( DdManager * dd, DdNode * bFunc, DdNode * bVarsCof, DdNode * bVarsAll ); +static unsigned Extra_CountMintermsSimple( DdNode * bFunc, unsigned max ); + +static void CountNodeVisits_rec( DdManager * dd, DdNode * aFunc, st_table * Visited ); +static void CollectNodesAndComputePaths_rec( DdManager * dd, DdNode * aFunc, DdNode * bCube, st_table * Visited, st_table * CutNodes ); + +/**AutomaticEnd***************************************************************/ + + +/*---------------------------------------------------------------------------*/ +/* Definition of exported functions */ +/*---------------------------------------------------------------------------*/ + +/**Function******************************************************************** + + Synopsis [Performs the binary encoding of the set of function using the given vars.] + + Description [Performs a straight binary encoding of the set of functions using + the variable cubes formed from the given set of variables. ] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * +Extra_bddEncodingBinary( + DdManager * dd, + DdNode ** pbFuncs, // pbFuncs is the array of columns to be encoded + int nFuncs, // nFuncs is the number of columns in the array + DdNode ** pbVars, // pbVars is the array of variables to use for the codes + int nVars ) // nVars is the column multiplicity, [log2(nFuncs)] +{ + int i; + DdNode * bResult; + DdNode * bCube, * bTemp, * bProd; + + assert( nVars >= Extra_Base2Log(nFuncs) ); + + bResult = b0; Cudd_Ref( bResult ); + for ( i = 0; i < nFuncs; i++ ) + { + bCube = Extra_bddBitsToCube( dd, i, nVars, pbVars, 1 ); Cudd_Ref( bCube ); + bProd = Cudd_bddAnd( dd, bCube, pbFuncs[i] ); Cudd_Ref( bProd ); + Cudd_RecursiveDeref( dd, bCube ); + + bResult = Cudd_bddOr( dd, bProd, bTemp = bResult ); Cudd_Ref( bResult ); + Cudd_RecursiveDeref( dd, bTemp ); + Cudd_RecursiveDeref( dd, bProd ); + } + + Cudd_Deref( bResult ); + return bResult; +} /* end of Extra_bddEncodingBinary */ + + +/**Function******************************************************************** + + Synopsis [Solves the column encoding problem using a sophisticated method.] + + Description [The encoding is based on the idea of deriving functions which + depend on only one variable, which corresponds to the case of non-disjoint + decompostion. It is assumed that the variables pCVars are ordered below the variables + representing the solumns, and the first variable pCVars[0] is the topmost one.] + + SideEffects [] + + SeeAlso [Extra_bddEncodingBinary] + +******************************************************************************/ + +DdNode * +Extra_bddEncodingNonStrict( + DdManager * dd, + DdNode ** pbColumns, // pbColumns is the array of columns to be encoded; + int nColumns, // nColumns is the number of columns in the array + DdNode * bVarsCol, // bVarsCol is the cube of variables on which the columns depend + DdNode ** pCVars, // pCVars is the array of variables to use for the codes + int nMulti, // nMulti is the column multiplicity, [log2(nColumns)] + int * pSimple ) // pSimple gets the number of code variables taken from the input varibles without change +{ + DdNode * bEncoded, * bResult; + int nVarsCol = Cudd_SupportSize(dd,bVarsCol); + long clk; + + // cannot work with more that 32-bit codes + assert( nMulti < 32 ); + + // perform the preliminary encoding using the straight binary code + bEncoded = Extra_bddEncodingBinary( dd, pbColumns, nColumns, pCVars, nMulti ); Cudd_Ref( bEncoded ); + //printf( "Node count = %d", Cudd_DagSize(bEncoded) ); + + // set the backgroup value for counting minterms + s_Terminal = b0; + // set the level of the encoding variables + s_EncodingVarsLevel = dd->invperm[pCVars[0]->index]; + + // the current number of backtracks + s_BackTracks = 0; + // the variables that are cofactored on the topmost level where everything starts (no vars) + s_Field[0][0] = b1; + // the size of the best set of "simple" encoding variables found so far + s_nVarsBest = 0; + + // set the relation to be accessible to traversal procedures + s_Encoded = bEncoded; + // the set of all vars to be accessible to traversal procedures + s_VarAll = bVarsCol; + // the column multiplicity + s_MultiStart = nMulti; + + + clk = clock(); + // find the simplest encoding + if ( nColumns > 2 ) + EvaluateEncodings_rec( dd, bVarsCol, nVarsCol, nMulti, 1 ); +// printf( "The number of backtracks = %d\n", s_BackTracks ); +// s_EncSearchTime += clock() - clk; + + // allocate the temporary storage for the columns + s_pbTemp = (DdNode **) malloc( nColumns * sizeof(DdNode *) ); + +// clk = clock(); + bResult = CreateTheCodes_rec( dd, bEncoded, 0, pCVars ); Cudd_Ref( bResult ); +// s_EncComputeTime += clock() - clk; + + // delocate the preliminarily encoded set + Cudd_RecursiveDeref( dd, bEncoded ); +// Cudd_RecursiveDeref( dd, aEncoded ); + + free( s_pbTemp ); + + *pSimple = s_nVarsBest; + Cudd_Deref( bResult ); + return bResult; +} + +/**Function******************************************************************** + + Synopsis [Collects the nodes under the cut and, for each node, computes the sum of paths leading to it from the root.] + + Description [The table returned contains the set of BDD nodes pointed to under the cut + and, for each node, the BDD of the sum of paths leading to this node from the root + The sums of paths in the table are referenced. CutLevel is the first DD level + considered to be under the cut.] + + SideEffects [] + + SeeAlso [Extra_bddNodePaths] + +******************************************************************************/ +st_table * Extra_bddNodePathsUnderCut( DdManager * dd, DdNode * bFunc, int CutLevel ) +{ + st_table * Visited; // temporary table to remember the visited nodes + st_table * CutNodes; // the result goes here + st_table * Result; // the result goes here + DdNode * aFunc; + + s_CutLevel = CutLevel; + + Result = st_init_table(st_ptrcmp,st_ptrhash); + // the terminal cases + if ( Cudd_IsConstant( bFunc ) ) + { + if ( bFunc == b1 ) + { + st_insert( Result, (char*)b1, (char*)b1 ); + Cudd_Ref( b1 ); + Cudd_Ref( b1 ); + } + else + { + st_insert( Result, (char*)b0, (char*)b0 ); + Cudd_Ref( b0 ); + Cudd_Ref( b0 ); + } + return Result; + } + + // create the ADD to simplify processing (no complemented edges) + aFunc = Cudd_BddToAdd( dd, bFunc ); Cudd_Ref( aFunc ); + + // Step 1: Start the tables and collect information about the nodes above the cut + // this information tells how many edges point to each node + Visited = st_init_table(st_ptrcmp,st_ptrhash); + CutNodes = st_init_table(st_ptrcmp,st_ptrhash); + + CountNodeVisits_rec( dd, aFunc, Visited ); + + // Step 2: Traverse the BDD using the visited table and compute the sum of paths + CollectNodesAndComputePaths_rec( dd, aFunc, b1, Visited, CutNodes ); + + // at this point the table of cut nodes is ready and the table of visited is useless + { + st_generator * gen; + DdNode * aNode; + traventry * p; + st_foreach_item( Visited, gen, (char**)&aNode, (char**)&p ) + { + Cudd_RecursiveDeref( dd, p->bSum ); + free( p ); + } + st_free_table( Visited ); + } + + // go through the table CutNodes and create the BDD and the path to be returned + { + st_generator * gen; + DdNode * aNode, * bNode, * bSum; + st_foreach_item( CutNodes, gen, (char**)&aNode, (char**)&bSum) + { + // aNode is not referenced, because aFunc is holding it + bNode = Cudd_addBddPattern( dd, aNode ); Cudd_Ref( bNode ); + st_insert( Result, (char*)bNode, (char*)bSum ); + // the new table takes both refs + } + st_free_table( CutNodes ); + } + + // dereference the ADD + Cudd_RecursiveDeref( dd, aFunc ); + + // return the table + return Result; + +} /* end of Extra_bddNodePathsUnderCut */ + +/**Function******************************************************************** + + Synopsis [Collects the nodes under the cut in the ADD starting from the given set of ADD nodes.] + + Description [Takes the array, paNodes, of ADD nodes to start the traversal, + the array, pbCubes, of BDD cubes to start the traversal with in each node, + and the number, nNodes, of ADD nodes and BDD cubes in paNodes and pbCubes. + Returns the number of columns found. Fills in paNodesRes (pbCubesRes) + with the set of ADD columns (BDD paths). These arrays should be allocated + by the user.] + + SideEffects [] + + SeeAlso [Extra_bddNodePaths] + +******************************************************************************/ +int Extra_bddNodePathsUnderCutArray( DdManager * dd, DdNode ** paNodes, DdNode ** pbCubes, int nNodes, DdNode ** paNodesRes, DdNode ** pbCubesRes, int CutLevel ) +{ + st_table * Visited; // temporary table to remember the visited nodes + st_table * CutNodes; // the nodes under the cut go here + int i, Counter; + + s_CutLevel = CutLevel; + + // there should be some nodes + assert( nNodes > 0 ); + if ( nNodes == 1 && Cudd_IsConstant( paNodes[0] ) ) + { + if ( paNodes[0] == a1 ) + { + paNodesRes[0] = a1; Cudd_Ref( a1 ); + pbCubesRes[0] = pbCubes[0]; Cudd_Ref( pbCubes[0] ); + } + else + { + paNodesRes[0] = a0; Cudd_Ref( a0 ); + pbCubesRes[0] = pbCubes[0]; Cudd_Ref( pbCubes[0] ); + } + return 1; + } + + // Step 1: Start the table and collect information about the nodes above the cut + // this information tells how many edges point to each node + CutNodes = st_init_table(st_ptrcmp,st_ptrhash); + Visited = st_init_table(st_ptrcmp,st_ptrhash); + + for ( i = 0; i < nNodes; i++ ) + CountNodeVisits_rec( dd, paNodes[i], Visited ); + + // Step 2: Traverse the BDD using the visited table and compute the sum of paths + for ( i = 0; i < nNodes; i++ ) + CollectNodesAndComputePaths_rec( dd, paNodes[i], pbCubes[i], Visited, CutNodes ); + + // at this point, the table of cut nodes is ready and the table of visited is useless + { + st_generator * gen; + DdNode * aNode; + traventry * p; + st_foreach_item( Visited, gen, (char**)&aNode, (char**)&p ) + { + Cudd_RecursiveDeref( dd, p->bSum ); + free( p ); + } + st_free_table( Visited ); + } + + // go through the table CutNodes and create the BDD and the path to be returned + { + st_generator * gen; + DdNode * aNode, * bSum; + Counter = 0; + st_foreach_item( CutNodes, gen, (char**)&aNode, (char**)&bSum) + { + paNodesRes[Counter] = aNode; Cudd_Ref( aNode ); + pbCubesRes[Counter] = bSum; + Counter++; + } + st_free_table( CutNodes ); + } + + // return the number of cofactors found + return Counter; + +} /* end of Extra_bddNodePathsUnderCutArray */ + +/**Function************************************************************* + + Synopsis [Collects all the BDD nodes into the table.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void extraCollectNodes( DdNode * Func, st_table * tNodes ) +{ + DdNode * FuncR; + FuncR = Cudd_Regular(Func); + if ( st_find_or_add( tNodes, (char*)FuncR, NULL ) ) + return; + if ( cuddIsConstant(FuncR) ) + return; + extraCollectNodes( cuddE(FuncR), tNodes ); + extraCollectNodes( cuddT(FuncR), tNodes ); +} + +/**Function************************************************************* + + Synopsis [Collects all the nodes of one DD into the table.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +st_table * Extra_CollectNodes( DdNode * Func ) +{ + st_table * tNodes; + tNodes = st_init_table( st_ptrcmp, st_ptrhash ); + extraCollectNodes( Func, tNodes ); + return tNodes; +} + +/**Function************************************************************* + + Synopsis [Updates the topmost level from which the given node is referenced.] + + Description [Takes the table which maps each BDD nodes (including the constants) + into the topmost level on which this node counts as a cofactor. Takes the topmost + level, on which this node counts as a cofactor (see Extra_ProfileWidthFast(). + Takes the node, for which the table entry should be updated.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void extraProfileUpdateTopLevel( st_table * tNodeTopRef, int TopLevelNew, DdNode * node ) +{ + int * pTopLevel; + + if ( st_find_or_add( tNodeTopRef, (char*)node, (char***)&pTopLevel ) ) + { // the node is already referenced + // the current top level should be updated if it is larger than the new level + if ( *pTopLevel > TopLevelNew ) + *pTopLevel = TopLevelNew; + } + else + { // the node is not referenced + // its level should be set to the current new level + *pTopLevel = TopLevelNew; + } +} +/**Function************************************************************* + + Synopsis [Fast computation of the BDD profile.] + + Description [The array to store the profile is given by the user and should + contain at least as many entries as there is the maximum of the BDD/ZDD + size of the manager PLUS ONE. + When we say that the widths of the DD on level L is W, we mean the following. + Let us create the cut between the level L-1 and the level L and count the number + of different DD nodes pointed to across the cut. This number is the width W. + From this it follows the on level 0, the width is equal to the number of external + pointers to the considered DDs. If there is only one DD, then the profile on + level 0 is always 1. If this DD is rooted in the topmost variable, then the width + on level 1 is always 2, etc. The width at the level equal to dd->size is the + number of terminal nodes in the DD. (Because we consider the first level #0 + and the last level #dd->size, the profile array should contain dd->size+1 entries.) + ] + + SideEffects [This procedure will not work for BDDs w/ complement edges, only for ADDs and ZDDs] + + SeeAlso [] + +***********************************************************************/ +int Extra_ProfileWidth( DdManager * dd, DdNode * Func, int * pProfile, int CutLevel ) +{ + st_generator * gen; + st_table * tNodeTopRef; // this table stores the top level from which this node is pointed to + st_table * tNodes; + DdNode * node; + DdNode * nodeR; + int LevelStart, Limit; + int i, size; + int WidthMax; + + // start the mapping table + tNodeTopRef = st_init_table(st_ptrcmp,st_ptrhash); + // add the topmost node to the profile + extraProfileUpdateTopLevel( tNodeTopRef, 0, Func ); + + // collect all nodes + tNodes = Extra_CollectNodes( Func ); + // go though all the nodes and set the top level the cofactors are pointed from +// Cudd_ForeachNode( dd, Func, genDD, node ) + st_foreach_item( tNodes, gen, (char**)&node, NULL ) + { +// assert( Cudd_Regular(node) ); // this procedure works only with ADD/ZDD (not BDD w/ compl.edges) + nodeR = Cudd_Regular(node); + if ( cuddIsConstant(nodeR) ) + continue; + // this node is not a constant - consider its cofactors + extraProfileUpdateTopLevel( tNodeTopRef, dd->perm[node->index]+1, cuddE(nodeR) ); + extraProfileUpdateTopLevel( tNodeTopRef, dd->perm[node->index]+1, cuddT(nodeR) ); + } + st_free_table( tNodes ); + + // clean the profile + size = ddMax(dd->size, dd->sizeZ) + 1; + for ( i = 0; i < size; i++ ) + pProfile[i] = 0; + + // create the profile + st_foreach_item( tNodeTopRef, gen, (char**)&node, (char**)&LevelStart ) + { + nodeR = Cudd_Regular(node); + Limit = (cuddIsConstant(nodeR))? dd->size: dd->perm[nodeR->index]; + for ( i = LevelStart; i <= Limit; i++ ) + pProfile[i]++; + } + + if ( CutLevel != -1 && CutLevel != 0 ) + size = CutLevel; + + // get the max width + WidthMax = 0; + for ( i = 0; i < size; i++ ) + if ( WidthMax < pProfile[i] ) + WidthMax = pProfile[i]; + + // deref the table + st_free_table( tNodeTopRef ); + + return WidthMax; +} /* end of Extra_ProfileWidth */ + + +/*---------------------------------------------------------------------------*/ +/* Definition of internal functions */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Definition of static functions */ +/*---------------------------------------------------------------------------*/ + +/**Function******************************************************************** + + Synopsis [Computes the non-strict codes when evaluation is finished.] + + Description [The information about the best code is stored in s_VarOrderBest, + which has s_nVarsBest entries.] + + SideEffects [None] + +******************************************************************************/ +DdNode * CreateTheCodes_rec( DdManager * dd, DdNode * bEncoded, int Level, DdNode ** pCVars ) +// bEncoded is the preliminarily encoded set of columns +// Level is the current level in the recursion +// pCVars are the variables to be used for encoding +{ + DdNode * bRes; + if ( Level == s_nVarsBest ) + { // the terminal case, when we need to remap the encoded function + // from the preliminary encoded variables to the new ones + st_table * CutNodes; + int nCols; +// double nMints; +/* +#ifdef _DEBUG + + { + DdNode * bTemp; + // make sure that the given number of variables is enough + bTemp = Cudd_bddExistAbstract( dd, bEncoded, s_VarAll ); Cudd_Ref( bTemp ); +// nMints = Cudd_CountMinterm( dd, bTemp, s_MultiStart ); + nMints = Extra_CountMintermsSimple( bTemp, (1< Extra_Power2( s_MultiStart-Level ) ) + { // the number of minterms is too large to encode the columns + // using the given minimum number of encoding variables + assert( 0 ); + } + Cudd_RecursiveDeref( dd, bTemp ); + } +#endif +*/ + // get the columns to be re-encoded + CutNodes = Extra_bddNodePathsUnderCut( dd, bEncoded, s_EncodingVarsLevel ); + // LUT size is the cut level because because the temporary encoding variables + // are above the functional variables - this is not true!!! + // the temporary variables are below! + + // put the entries from the table into the temporary array + { + st_generator * gen; + DdNode * bColumn, * bCode; + nCols = 0; + st_foreach_item( CutNodes, gen, (char**)&bCode, (char**)&bColumn ) + { + if ( bCode == b0 ) + { // the unused part of the columns + Cudd_RecursiveDeref( dd, bColumn ); + Cudd_RecursiveDeref( dd, bCode ); + continue; + } + else + { + s_pbTemp[ nCols ] = bColumn; // takes ref + Cudd_RecursiveDeref( dd, bCode ); + nCols++; + } + } + st_free_table( CutNodes ); +// assert( nCols == (int)nMints ); + } + + // encode the columns + if ( s_MultiStart-Level == 0 ) // we reached the bottom level of recursion + { + assert( nCols == 1 ); +// assert( (int)nMints == 1 ); + bRes = s_pbTemp[0]; Cudd_Ref( bRes ); + } + else + { + bRes = Extra_bddEncodingBinary( dd, s_pbTemp, nCols, pCVars+Level, s_MultiStart-Level ); Cudd_Ref( bRes ); + } + + // deref the columns + { + int i; + for ( i = 0; i < nCols; i++ ) + Cudd_RecursiveDeref( dd, s_pbTemp[i] ); + } + } + else + { + // cofactor the problem as specified in the best solution + DdNode * bCof0, * bCof1; + DdNode * bRes0, * bRes1; + DdNode * bProd0, * bProd1; + DdNode * bTemp; + DdNode * bVarNext = dd->vars[ s_VarOrderBest[Level] ]; + + bCof0 = Cudd_Cofactor( dd, bEncoded, Cudd_Not( bVarNext ) ); Cudd_Ref( bCof0 ); + bCof1 = Cudd_Cofactor( dd, bEncoded, bVarNext ); Cudd_Ref( bCof1 ); + + // call recursively + bRes0 = CreateTheCodes_rec( dd, bCof0, Level+1, pCVars ); Cudd_Ref( bRes0 ); + bRes1 = CreateTheCodes_rec( dd, bCof1, Level+1, pCVars ); Cudd_Ref( bRes1 ); + + Cudd_RecursiveDeref( dd, bCof0 ); + Cudd_RecursiveDeref( dd, bCof1 ); + + // compose the result using the identity (bVarNext <=> pCVars[Level]) - this is wrong! + // compose the result as follows: x'y'F0 + xyF1 + bProd0 = Cudd_bddAnd( dd, Cudd_Not(bVarNext), Cudd_Not(pCVars[Level]) ); Cudd_Ref( bProd0 ); + bProd1 = Cudd_bddAnd( dd, bVarNext , pCVars[Level] ); Cudd_Ref( bProd1 ); + + bProd0 = Cudd_bddAnd( dd, bTemp = bProd0, bRes0 ); Cudd_Ref( bProd0 ); + Cudd_RecursiveDeref( dd, bTemp ); + Cudd_RecursiveDeref( dd, bRes0 ); + + bProd1 = Cudd_bddAnd( dd, bTemp = bProd1, bRes1 ); Cudd_Ref( bProd1 ); + Cudd_RecursiveDeref( dd, bTemp ); + Cudd_RecursiveDeref( dd, bRes1 ); + + bRes = Cudd_bddOr( dd, bProd0, bProd1 ); Cudd_Ref( bRes ); + + Cudd_RecursiveDeref( dd, bProd0 ); + Cudd_RecursiveDeref( dd, bProd1 ); + } + Cudd_Deref( bRes ); + return bRes; +} + +/**Function******************************************************************** + + Synopsis [Computes the current set of variables and counts the number of minterms.] + + Description [Old implementation.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +void EvaluateEncodings_rec( DdManager * dd, DdNode * bVarsCol, int nVarsCol, int nMulti, int Level ) +// bVarsCol is the set of remaining variables +// nVarsCol is the number of remaining variables +// nMulti is the number of encoding variables to be used +// Level is the level of recursion, from which this function is called +// if we successfully finish this procedure, Level also stands for how many encoding variabled we saved +{ + int i, k; + int nEntries = (1<<(Level-1)); // the number of entries in the field of the previous level + DdNode * bVars0, * bVars1; // the cofactors + unsigned nMint0, nMint1; // the number of minterms + DdNode * bTempV; + DdNode * bVarTop; + int fBreak; + + + // there is no need to search above this level + if ( Level > s_MaxDepth ) + return; + + // if there are no variables left, quit the research + if ( bVarsCol == b1 ) + return; + + if ( s_BackTracks > s_BackTrackLimit ) + return; + + s_BackTracks++; + + // otherwise, go through the remaining variables + for ( bTempV = bVarsCol; bTempV != b1; bTempV = cuddT(bTempV) ) + { + // the currently tested variable + bVarTop = dd->vars[bTempV->index]; + + // put it into the array + s_VarOrderCur[Level-1] = bTempV->index; + + // go through the entries and fill them out by cofactoring + fBreak = 0; + for ( i = 0; i < nEntries; i++ ) + { + bVars0 = ComputeVarSetAndCountMinterms( dd, s_Field[Level-1][i], Cudd_Not(bVarTop), &nMint0 ); + Cudd_Ref( bVars0 ); + + if ( nMint0 > Extra_Power2( nMulti-1 ) ) + { + // there is no way to encode - dereference and return + Cudd_RecursiveDeref( dd, bVars0 ); + fBreak = 1; + break; + } + + bVars1 = ComputeVarSetAndCountMinterms( dd, s_Field[Level-1][i], bVarTop, &nMint1 ); + Cudd_Ref( bVars1 ); + + if ( nMint1 > Extra_Power2( nMulti-1 ) ) + { + // there is no way to encode - dereference and return + Cudd_RecursiveDeref( dd, bVars0 ); + Cudd_RecursiveDeref( dd, bVars1 ); + fBreak = 1; + break; + } + + // otherwise, add these two cofactors + s_Field[Level][2*i + 0] = bVars0; // takes ref + s_Field[Level][2*i + 1] = bVars1; // takes ref + } + + if ( !fBreak ) + { + DdNode * bVarsRem; + // if we ended up here, it means that the cofactors w.r.t. variable bVarTop satisfy the condition + // save this situation + if ( s_nVarsBest < Level ) + { + s_nVarsBest = Level; + // copy the variable assignment + for ( k = 0; k < Level; k++ ) + s_VarOrderBest[k] = s_VarOrderCur[k]; + } + + // call recursively + // get the new variable set + if ( nMulti-1 > 0 ) + { + bVarsRem = Cudd_bddExistAbstract( dd, bVarsCol, bVarTop ); Cudd_Ref( bVarsRem ); + EvaluateEncodings_rec( dd, bVarsRem, nVarsCol-1, nMulti-1, Level+1 ); + Cudd_RecursiveDeref( dd, bVarsRem ); + } + } + + // deref the contents of the array + for ( k = 0; k < i; k++ ) + { + Cudd_RecursiveDeref( dd, s_Field[Level][2*k + 0] ); + Cudd_RecursiveDeref( dd, s_Field[Level][2*k + 1] ); + } + + // if the solution is found, there is no need to continue + if ( s_nVarsBest == s_MaxDepth ) + return; + + // if the solution is found, there is no need to continue + if ( s_nVarsBest == s_MultiStart ) + return; + } + // at this point, we have tried all possible directions in the space of variables +} + +/**Function******************************************************************** + + Synopsis [Computes the current set of variables and counts the number of minterms.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * ComputeVarSetAndCountMinterms( DdManager * dd, DdNode * bVars, DdNode * bVarTop, unsigned * Cost ) +// takes bVars - the variables cofactored so far (some of them may be in negative polarity) +// bVarTop - the topmost variable w.r.t. which to cofactor (may be in negative polarity) +// returns the cost and the new set of variables (bVars & bVarTop) +{ + DdNode * bVarsRes; + + // get the resulting set of variables + bVarsRes = Cudd_bddAnd( dd, bVars, bVarTop ); Cudd_Ref( bVarsRes ); + + // increment signature before calling Cudd_CountCofactorMinterms() + s_Signature++; + *Cost = Extra_CountCofactorMinterms( dd, s_Encoded, bVarsRes, s_VarAll ); + + Cudd_Deref( bVarsRes ); +// s_CountCalls++; + return bVarsRes; +} + +/**Function******************************************************************** + + Synopsis [Computes the current set of variables and counts the number of minterms.] + + Description [The old implementation, which is approximately 4 times slower.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * ComputeVarSetAndCountMinterms2( DdManager * dd, DdNode * bVars, DdNode * bVarTop, unsigned * Cost ) +{ + DdNode * bVarsRes; + DdNode * bCof, * bFun; + + bVarsRes = Cudd_bddAnd( dd, bVars, bVarTop ); Cudd_Ref( bVarsRes ); + + bCof = Cudd_Cofactor( dd, s_Encoded, bVarsRes ); Cudd_Ref( bCof ); + bFun = Cudd_bddExistAbstract( dd, bCof, s_VarAll ); Cudd_Ref( bFun ); + *Cost = (unsigned)Cudd_CountMinterm( dd, bFun, s_MultiStart ); + Cudd_RecursiveDeref( dd, bFun ); + Cudd_RecursiveDeref( dd, bCof ); + + Cudd_Deref( bVarsRes ); +// s_CountCalls++; + return bVarsRes; +} + + +/**Function******************************************************************** + + Synopsis [Counts the number of encoding minterms pointed to by the cofactor of the function.] + + Description [] + + SideEffects [None] + +******************************************************************************/ +unsigned Extra_CountCofactorMinterms( DdManager * dd, DdNode * bFunc, DdNode * bVarsCof, DdNode * bVarsAll ) +// this function computes how many minterms depending on the encoding variables +// are there in the cofactor of bFunc w.r.t. variables bVarsCof +// bFunc is assumed to depend on variables s_VarsAll +// the variables s_VarsAll should be ordered above the encoding variables +{ + unsigned HKey; + DdNode * bFuncR; + + // if the function is zero, there are no minterms +// if ( bFunc == b0 ) +// return 0; + +// if ( st_lookup(Visited, (char*)bFunc, NULL) ) +// return 0; + +// HKey = hashKey2c( s_Signature, bFuncR ); +// if ( HHTable1[HKey].Sign == s_Signature && HHTable1[HKey].Arg1 == bFuncR ) // this node is visited +// return 0; + + + // check the hash-table + bFuncR = Cudd_Regular(bFunc); +// HKey = hashKey2( s_Signature, bFuncR, _TABLESIZE_COF ); + HKey = hashKey2( s_Signature, bFunc, _TABLESIZE_COF ); + for ( ; HHTable1[HKey].Sign == s_Signature; HKey = (HKey+1) % _TABLESIZE_COF ) +// if ( HHTable1[HKey].Arg1 == bFuncR ) // this node is visited + if ( HHTable1[HKey].Arg1 == bFunc ) // this node is visited + return 0; + + + // if the function is already the code + if ( dd->perm[bFuncR->index] >= s_EncodingVarsLevel ) + { +// st_insert(Visited, (char*)bFunc, NULL); + +// HHTable1[HKey].Sign = s_Signature; +// HHTable1[HKey].Arg1 = bFuncR; + + assert( HHTable1[HKey].Sign != s_Signature ); + HHTable1[HKey].Sign = s_Signature; +// HHTable1[HKey].Arg1 = bFuncR; + HHTable1[HKey].Arg1 = bFunc; + + return Extra_CountMintermsSimple( bFunc, (1<perm[bFuncR->index]; + int LevelC = cuddI(dd,bVarsCofR->index); + int LevelA = dd->perm[bVarsAll->index]; + + int LevelTop = LevelF; + + if ( LevelTop > LevelC ) + LevelTop = LevelC; + + if ( LevelTop > LevelA ) + LevelTop = LevelA; + + // the top var in the function or in cofactoring vars always belongs to the set of all vars + assert( !( LevelTop == LevelF || LevelTop == LevelC ) || LevelTop == LevelA ); + + // cofactor the function + if ( LevelTop == LevelF ) + { + if ( bFuncR != bFunc ) // bFunc is complemented + { + bFunc0 = Cudd_Not( cuddE(bFuncR) ); + bFunc1 = Cudd_Not( cuddT(bFuncR) ); + } + else + { + bFunc0 = cuddE(bFuncR); + bFunc1 = cuddT(bFuncR); + } + } + else // bVars is higher in the variable order + bFunc0 = bFunc1 = bFunc; + + // cofactor the cube + if ( LevelTop == LevelC ) + { + if ( bVarsCofR != bVarsCof ) // bFunc is complemented + { + bVarsCof0 = Cudd_Not( cuddE(bVarsCofR) ); + bVarsCof1 = Cudd_Not( cuddT(bVarsCofR) ); + } + else + { + bVarsCof0 = cuddE(bVarsCofR); + bVarsCof1 = cuddT(bVarsCofR); + } + } + else // bVars is higher in the variable order + bVarsCof0 = bVarsCof1 = bVarsCof; + + // there are two cases: + // (1) the top variable belongs to the cofactoring variables + // (2) the top variable does not belong to the cofactoring variables + + // (1) the top variable belongs to the cofactoring variables + Res = 0; + if ( LevelTop == LevelC ) + { + if ( bVarsCof1 == b0 ) // this is a negative cofactor + { + if ( bFunc0 != b0 ) + Res = Extra_CountCofactorMinterms( dd, bFunc0, bVarsCof0, cuddT(bVarsAll) ); + } + else // this is a positive cofactor + { + if ( bFunc1 != b0 ) + Res = Extra_CountCofactorMinterms( dd, bFunc1, bVarsCof1, cuddT(bVarsAll) ); + } + } + else + { + if ( bFunc0 != b0 ) + Res += Extra_CountCofactorMinterms( dd, bFunc0, bVarsCof0, cuddT(bVarsAll) ); + + if ( bFunc1 != b0 ) + Res += Extra_CountCofactorMinterms( dd, bFunc1, bVarsCof1, cuddT(bVarsAll) ); + } + +// st_insert(Visited, (char*)bFunc, NULL); + +// HHTable1[HKey].Sign = s_Signature; +// HHTable1[HKey].Arg1 = bFuncR; + + // skip through the entries with the same signatures + // (these might have been created at the time of recursive calls) + for ( ; HHTable1[HKey].Sign == s_Signature; HKey = (HKey+1) % _TABLESIZE_COF ); + assert( HHTable1[HKey].Sign != s_Signature ); + HHTable1[HKey].Sign = s_Signature; +// HHTable1[HKey].Arg1 = bFuncR; + HHTable1[HKey].Arg1 = bFunc; + + return Res; + } +} + +/**Function******************************************************************** + + Synopsis [Counts the number of minterms.] + + Description [This function counts minterms for functions up to 32 variables + using a local cache. The terminal value (s_Termina) should be adjusted for + BDDs and ADDs.] + + SideEffects [None] + +******************************************************************************/ +unsigned Extra_CountMintermsSimple( DdNode * bFunc, unsigned max ) +{ + unsigned HKey; + + // normalize + if ( Cudd_IsComplement(bFunc) ) + return max - Extra_CountMintermsSimple( Cudd_Not(bFunc), max ); + + // now it is known that the function is not complemented + if ( cuddIsConstant(bFunc) ) + return ((bFunc==s_Terminal)? 0: max); + + // check cache + HKey = hashKey2( bFunc, max, _TABLESIZE_MINT ); + if ( HHTable2[HKey].Arg1 == bFunc && HHTable2[HKey].Arg2 == max ) + return HHTable2[HKey].Res; + else + { + // min = min0/2 + min1/2; + unsigned min = (Extra_CountMintermsSimple( cuddE(bFunc), max ) >> 1) + + (Extra_CountMintermsSimple( cuddT(bFunc), max ) >> 1); + + HHTable2[HKey].Arg1 = bFunc; + HHTable2[HKey].Arg2 = max; + HHTable2[HKey].Res = min; + + return min; + } +} /* end of Extra_CountMintermsSimple */ + + +/**Function******************************************************************** + + Synopsis [Visits the nodes.] + + Description [Visits the nodes above the cut and the nodes pointed to below the cut; + collects the visited nodes, counts how many times each node is visited, and sets + the path-sum to be the constant zero BDD.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +void CountNodeVisits_rec( DdManager * dd, DdNode * aFunc, st_table * Visited ) + +{ + traventry * p; + char **slot; + if ( st_find_or_add(Visited, (char*)aFunc, &slot) ) + { // the entry already exists + p = (traventry*) *slot; + // increment the counter of incoming edges + p->nEdges++; + return; + } + // this node has not been visited + assert( !Cudd_IsComplement(aFunc) ); + + // create the new traversal entry + p = (traventry *) malloc( sizeof(traventry) ); + // set the initial sum of edges to zero BDD + p->bSum = b0; Cudd_Ref( b0 ); + // set the starting number of incoming edges + p->nEdges = 1; + // set this entry into the slot + *slot = (char*)p; + + // recur if the node is above the cut + if ( cuddI(dd,aFunc->index) < s_CutLevel ) + { + CountNodeVisits_rec( dd, cuddE(aFunc), Visited ); + CountNodeVisits_rec( dd, cuddT(aFunc), Visited ); + } +} /* end of CountNodeVisits_rec */ + + +/**Function******************************************************************** + + Synopsis [Revisits the nodes and computes the paths.] + + Description [This function visits the nodes above the cut having the goal of + summing all the incomming BDD edges; when this function comes across the node + below the cut, it saves this node in the CutNode table.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +void CollectNodesAndComputePaths_rec( DdManager * dd, DdNode * aFunc, DdNode * bCube, st_table * Visited, st_table * CutNodes ) +{ + // find the node in the visited table + DdNode * bTemp; + traventry * p; + char **slot; + if ( st_find_or_add(Visited, (char*)aFunc, &slot) ) + { // the node is found + // get the pointer to the traversal entry + p = (traventry*) *slot; + + // make sure that the counter of incoming edges is positive + assert( p->nEdges > 0 ); + + // add the cube to the currently accumulated cubes + p->bSum = Cudd_bddOr( dd, bTemp = p->bSum, bCube ); Cudd_Ref( p->bSum ); + Cudd_RecursiveDeref( dd, bTemp ); + + // decrement the number of visits + p->nEdges--; + + // if more visits to this node are expected, return + if ( p->nEdges ) + return; + else // if ( p->nEdges == 0 ) + { // this is the last visit - propagate the cube + + // check where this node is + if ( cuddI(dd,aFunc->index) < s_CutLevel ) + { // the node is above the cut + DdNode * bCube0, * bCube1; + + // get the top-most variable + DdNode * bVarTop = dd->vars[aFunc->index]; + + // compute the propagated cubes + bCube0 = Cudd_bddAnd( dd, p->bSum, Cudd_Not( bVarTop ) ); Cudd_Ref( bCube0 ); + bCube1 = Cudd_bddAnd( dd, p->bSum, bVarTop ); Cudd_Ref( bCube1 ); + + // call recursively + CollectNodesAndComputePaths_rec( dd, cuddE(aFunc), bCube0, Visited, CutNodes ); + CollectNodesAndComputePaths_rec( dd, cuddT(aFunc), bCube1, Visited, CutNodes ); + + // dereference the cubes + Cudd_RecursiveDeref( dd, bCube0 ); + Cudd_RecursiveDeref( dd, bCube1 ); + return; + } + else + { // the node is below the cut + // add this node to the cut node table, if it is not yet there + +// DdNode * bNode; +// bNode = Cudd_addBddPattern( dd, aFunc ); Cudd_Ref( bNode ); + if ( st_find_or_add(CutNodes, (char*)aFunc, &slot) ) + { // the node exists - should never happen + assert( 0 ); + } + *slot = (char*) p->bSum; Cudd_Ref( p->bSum ); + // the table takes the reference of bNode + return; + } + } + } + + // the node does not exist in the visited table - should never happen + assert(0); + +} /* end of CollectNodesAndComputePaths_rec */ + + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// diff --git a/src/misc/extra/extraBddKmap.c b/src/misc/extra/extraBddKmap.c new file mode 100644 index 00000000..bb43db68 --- /dev/null +++ b/src/misc/extra/extraBddKmap.c @@ -0,0 +1,783 @@ +/**CFile**************************************************************** + + FileName [extraBddKmap.c] + + PackageName [extra] + + Synopsis [Visualizing the K-map.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 2.0. Started - September 1, 2003.] + + Revision [$Id: extraBddKmap.c,v 1.0 2003/05/21 18:03:50 alanmi Exp $] + +***********************************************************************/ + +/// K-map visualization using pseudo graphics /// +/// Version 1.0. Started - August 20, 2000 /// +/// Version 2.0. Added to EXTRA - July 17, 2001 /// + +#include "extra.h" + +/*---------------------------------------------------------------------------*/ +/* Constant declarations */ +/*---------------------------------------------------------------------------*/ + +// the maximum number of variables in the Karnaugh Map +#define MAXVARS 20 + +/* +// single line +#define SINGLE_VERTICAL (char)179 +#define SINGLE_HORIZONTAL (char)196 +#define SINGLE_TOP_LEFT (char)218 +#define SINGLE_TOP_RIGHT (char)191 +#define SINGLE_BOT_LEFT (char)192 +#define SINGLE_BOT_RIGHT (char)217 + +// double line +#define DOUBLE_VERTICAL (char)186 +#define DOUBLE_HORIZONTAL (char)205 +#define DOUBLE_TOP_LEFT (char)201 +#define DOUBLE_TOP_RIGHT (char)187 +#define DOUBLE_BOT_LEFT (char)200 +#define DOUBLE_BOT_RIGHT (char)188 + +// line intersections +#define SINGLES_CROSS (char)197 +#define DOUBLES_CROSS (char)206 +#define S_HOR_CROSS_D_VER (char)215 +#define S_VER_CROSS_D_HOR (char)216 + +// single line joining +#define S_JOINS_S_VER_LEFT (char)180 +#define S_JOINS_S_VER_RIGHT (char)195 +#define S_JOINS_S_HOR_TOP (char)193 +#define S_JOINS_S_HOR_BOT (char)194 + +// double line joining +#define D_JOINS_D_VER_LEFT (char)185 +#define D_JOINS_D_VER_RIGHT (char)204 +#define D_JOINS_D_HOR_TOP (char)202 +#define D_JOINS_D_HOR_BOT (char)203 + +// single line joining double line +#define S_JOINS_D_VER_LEFT (char)182 +#define S_JOINS_D_VER_RIGHT (char)199 +#define S_JOINS_D_HOR_TOP (char)207 +#define S_JOINS_D_HOR_BOT (char)209 +*/ + +// single line +#define SINGLE_VERTICAL (char)'|' +#define SINGLE_HORIZONTAL (char)'-' +#define SINGLE_TOP_LEFT (char)'+' +#define SINGLE_TOP_RIGHT (char)'+' +#define SINGLE_BOT_LEFT (char)'+' +#define SINGLE_BOT_RIGHT (char)'+' + +// double line +#define DOUBLE_VERTICAL (char)'|' +#define DOUBLE_HORIZONTAL (char)'-' +#define DOUBLE_TOP_LEFT (char)'+' +#define DOUBLE_TOP_RIGHT (char)'+' +#define DOUBLE_BOT_LEFT (char)'+' +#define DOUBLE_BOT_RIGHT (char)'+' + +// line intersections +#define SINGLES_CROSS (char)'+' +#define DOUBLES_CROSS (char)'+' +#define S_HOR_CROSS_D_VER (char)'+' +#define S_VER_CROSS_D_HOR (char)'+' + +// single line joining +#define S_JOINS_S_VER_LEFT (char)'+' +#define S_JOINS_S_VER_RIGHT (char)'+' +#define S_JOINS_S_HOR_TOP (char)'+' +#define S_JOINS_S_HOR_BOT (char)'+' + +// double line joining +#define D_JOINS_D_VER_LEFT (char)'+' +#define D_JOINS_D_VER_RIGHT (char)'+' +#define D_JOINS_D_HOR_TOP (char)'+' +#define D_JOINS_D_HOR_BOT (char)'+' + +// single line joining double line +#define S_JOINS_D_VER_LEFT (char)'+' +#define S_JOINS_D_VER_RIGHT (char)'+' +#define S_JOINS_D_HOR_TOP (char)'+' +#define S_JOINS_D_HOR_BOT (char)'+' + + +// other symbols +#define UNDERSCORE (char)95 +//#define SYMBOL_ZERO (char)248 // degree sign +//#define SYMBOL_ZERO (char)'o' +#define SYMBOL_ZERO (char)' ' +#define SYMBOL_ONE (char)'1' +#define SYMBOL_DC (char)'-' +#define SYMBOL_OVERLAP (char)'?' + +// full cells and half cells +#define CELL_FREE (char)32 +#define CELL_FULL (char)219 +#define HALF_UPPER (char)223 +#define HALF_LOWER (char)220 +#define HALF_LEFT (char)221 +#define HALF_RIGHT (char)222 + + +/*---------------------------------------------------------------------------*/ +/* Structure declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Type declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Variable declarations */ +/*---------------------------------------------------------------------------*/ + +// the array of BDD variables used internally +static DdNode * s_XVars[MAXVARS]; + +// flag which determines where the horizontal variable names are printed +static int fHorizontalVarNamesPrintedAbove = 1; + +/*---------------------------------------------------------------------------*/ +/* Macro declarations */ +/*---------------------------------------------------------------------------*/ + + +/**AutomaticStart*************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Static function prototypes */ +/*---------------------------------------------------------------------------*/ + +// Oleg's way of generating the gray code +static int GrayCode( int BinCode ); +static int BinCode ( int GrayCode ); + +/**AutomaticEnd***************************************************************/ + + +/*---------------------------------------------------------------------------*/ +/* Definition of exported functions */ +/*---------------------------------------------------------------------------*/ + + +/**Function******************************************************************** + + Synopsis [Prints the K-map of the function.] + + Description [If the pointer to the array of variables XVars is NULL, + fSuppType determines how the support will be determined. + fSuppType == 0 -- takes the first nVars of the manager + fSuppType == 1 -- takes the topmost nVars of the manager + fSuppType == 2 -- determines support from the on-set and the offset + ] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +void Extra_PrintKMap( + FILE * Output, /* the output stream */ + DdManager * dd, + DdNode * OnSet, + DdNode * OffSet, + int nVars, + DdNode ** XVars, + int fSuppType, /* the flag which determines how support is computed */ + char ** pVarNames ) +{ + int d, p, n, s, v, h, w; + int nVarsVer; + int nVarsHor; + int nCellsVer; + int nCellsHor; + int nSkipSpaces; + + // make sure that on-set and off-set do not overlap + if ( !Cudd_bddLeq( dd, OnSet, Cudd_Not(OffSet) ) ) + { + fprintf( Output, "PrintKMap(): The on-set and the off-set overlap\n" ); + return; + } +/* + if ( OnSet == b1 ) + { + fprintf( Output, "PrintKMap(): Constant 1\n" ); + return; + } + if ( OffSet == b1 ) + { + fprintf( Output, "PrintKMap(): Constant 0\n" ); + return; + } +*/ + if ( nVars < 0 || nVars > MAXVARS ) + { + fprintf( Output, "PrintKMap(): The number of variables is less than zero or more than %d\n", MAXVARS ); + return; + } + + // determine the support if it is not given + if ( XVars == NULL ) + { + if ( fSuppType == 0 ) + { // assume that the support includes the first nVars of the manager + assert( nVars ); + for ( v = 0; v < nVars; v++ ) + s_XVars[v] = Cudd_bddIthVar( dd, v ); + } + else if ( fSuppType == 1 ) + { // assume that the support includes the topmost nVars of the manager + assert( nVars ); + for ( v = 0; v < nVars; v++ ) + s_XVars[v] = Cudd_bddIthVar( dd, dd->invperm[v] ); + } + else // determine the support + { + DdNode * SuppOn, * SuppOff, * Supp; + int cVars = 0; + DdNode * TempSupp; + + // determine support + SuppOn = Cudd_Support( dd, OnSet ); Cudd_Ref( SuppOn ); + SuppOff = Cudd_Support( dd, OffSet ); Cudd_Ref( SuppOff ); + Supp = Cudd_bddAnd( dd, SuppOn, SuppOff ); Cudd_Ref( Supp ); + Cudd_RecursiveDeref( dd, SuppOn ); + Cudd_RecursiveDeref( dd, SuppOff ); + + nVars = Cudd_SupportSize( dd, Supp ); + if ( nVars > MAXVARS ) + { + fprintf( Output, "PrintKMap(): The number of variables is more than %d\n", MAXVARS ); + Cudd_RecursiveDeref( dd, Supp ); + return; + } + + // assign variables + for ( TempSupp = Supp; TempSupp != dd->one; TempSupp = Cudd_T(TempSupp), cVars++ ) + s_XVars[cVars] = Cudd_bddIthVar( dd, TempSupp->index ); + + Cudd_RecursiveDeref( dd, TempSupp ); + } + } + else + { + // copy variables + assert( XVars ); + for ( v = 0; v < nVars; v++ ) + s_XVars[v] = XVars[v]; + } + + //////////////////////////////////////////////////////////////////// + // determine the Karnaugh map parameters + nVarsVer = nVars/2; + nVarsHor = nVars - nVarsVer; + nCellsVer = (1< MAXVARS ) + { + fprintf( Output, "PrintKMap(): The number of variables is less than zero or more than %d\n", MAXVARS ); + return; + } + + + //////////////////////////////////////////////////////////////////// + // determine the Karnaugh map parameters + nVarsVer = nXVars; + nVarsHor = nYVars; + nCellsVer = (1<> 1 ); +} + +/**Function******************************************************************** + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +int BinCode ( int GrayCode ) +{ + int bc = GrayCode; + while( GrayCode >>= 1 ) bc ^= GrayCode; + return bc; +} + + diff --git a/src/misc/extra/extraBddMisc.c b/src/misc/extra/extraBddMisc.c new file mode 100644 index 00000000..a3320ad3 --- /dev/null +++ b/src/misc/extra/extraBddMisc.c @@ -0,0 +1,1614 @@ +/**CFile**************************************************************** + + FileName [extraBddMisc.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [extra] + + Synopsis [DD-based utilities.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: extraBddMisc.c,v 1.4 2005/10/04 00:19:54 alanmi Exp $] + +***********************************************************************/ + +#include "extra.h" + +/*---------------------------------------------------------------------------*/ +/* Constant declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Stucture declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Type declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Variable declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Macro declarations */ +/*---------------------------------------------------------------------------*/ + + +/**AutomaticStart*************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Static function prototypes */ +/*---------------------------------------------------------------------------*/ + +// file "extraDdTransfer.c" +static DdNode * extraTransferPermuteRecur( DdManager * ddS, DdManager * ddD, DdNode * f, st_table * table, int * Permute ); +static DdNode * extraTransferPermute( DdManager * ddS, DdManager * ddD, DdNode * f, int * Permute ); +static DdNode * cuddBddPermuteRecur ARGS( ( DdManager * manager, DdHashTable * table, DdNode * node, int *permut ) ); + +// file "cuddUtils.c" +static void ddSupportStep(DdNode *f, int *support); +static void ddClearFlag(DdNode *f); + +static DdNode* extraZddPrimes( DdManager *dd, DdNode* F ); + +/**AutomaticEnd***************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Definition of exported functions */ +/*---------------------------------------------------------------------------*/ + +/**Function******************************************************************** + + Synopsis [Convert a {A,B}DD from a manager to another with variable remapping.] + + Description [Convert a {A,B}DD from a manager to another one. The orders of the + variables in the two managers may be different. Returns a + pointer to the {A,B}DD in the destination manager if successful; NULL + otherwise. The i-th entry in the array Permute tells what is the index + of the i-th variable from the old manager in the new manager.] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_TransferPermute( DdManager * ddSource, DdManager * ddDestination, DdNode * f, int * Permute ) +{ + DdNode * bRes; + do + { + ddDestination->reordered = 0; + bRes = extraTransferPermute( ddSource, ddDestination, f, Permute ); + } + while ( ddDestination->reordered == 1 ); + return ( bRes ); + +} /* end of Extra_TransferPermute */ + +/**Function******************************************************************** + + Synopsis [Transfers the BDD from one manager into another level by level.] + + Description [Transfers the BDD from one manager into another while + preserving the correspondence between variables level by level.] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_TransferLevelByLevel( DdManager * ddSource, DdManager * ddDestination, DdNode * f ) +{ + DdNode * bRes; + int * pPermute; + int nMin, nMax, i; + + nMin = ddMin(ddSource->size, ddDestination->size); + nMax = ddMax(ddSource->size, ddDestination->size); + pPermute = ALLOC( int, nMax ); + // set up the variable permutation + for ( i = 0; i < nMin; i++ ) + pPermute[ ddSource->invperm[i] ] = ddDestination->invperm[i]; + if ( ddSource->size > ddDestination->size ) + { + for ( ; i < nMax; i++ ) + pPermute[ ddSource->invperm[i] ] = -1; + } + bRes = Extra_TransferPermute( ddSource, ddDestination, f, pPermute ); + FREE( pPermute ); + return bRes; +} + +/**Function******************************************************************** + + Synopsis [Remaps the function to depend on the topmost variables on the manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_bddRemapUp( + DdManager * dd, + DdNode * bF ) +{ + int * pPermute; + DdNode * bSupp, * bTemp, * bRes; + int Counter; + + pPermute = ALLOC( int, dd->size ); + + // get support + bSupp = Cudd_Support( dd, bF ); Cudd_Ref( bSupp ); + + // create the variable map + // to remap the DD into the upper part of the manager + Counter = 0; + for ( bTemp = bSupp; bTemp != dd->one; bTemp = cuddT(bTemp) ) + pPermute[bTemp->index] = dd->invperm[Counter++]; + + // transfer the BDD and remap it + bRes = Cudd_bddPermute( dd, bF, pPermute ); Cudd_Ref( bRes ); + + // remove support + Cudd_RecursiveDeref( dd, bSupp ); + + // return + Cudd_Deref( bRes ); + free( pPermute ); + return bRes; +} + +/**Function******************************************************************** + + Synopsis [Moves the BDD by the given number of variables up or down.] + + Description [] + + SideEffects [] + + SeeAlso [Extra_bddShift] + +******************************************************************************/ +DdNode * Extra_bddMove( + DdManager * dd, /* the DD manager */ + DdNode * bF, + int nVars) +{ + DdNode * res; + DdNode * bVars; + if ( nVars == 0 ) + return bF; + if ( Cudd_IsConstant(bF) ) + return bF; + assert( nVars <= dd->size ); + if ( nVars > 0 ) + bVars = dd->vars[nVars]; + else + bVars = Cudd_Not(dd->vars[-nVars]); + + do { + dd->reordered = 0; + res = extraBddMove( dd, bF, bVars ); + } while (dd->reordered == 1); + return(res); + +} /* end of Extra_bddMove */ + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_StopManager( DdManager * dd ) +{ + int RetValue; + // check for remaining references in the package + RetValue = Cudd_CheckZeroRef( dd ); + if ( RetValue > 0 ) + printf( "\nThe number of referenced nodes = %d\n\n", RetValue ); +// Cudd_PrintInfo( dd, stdout ); + Cudd_Quit( dd ); +} + +/**Function******************************************************************** + + Synopsis [Outputs the BDD in a readable format.] + + Description [] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +void Extra_bddPrint( DdManager * dd, DdNode * F ) +{ + DdGen * Gen; + int * Cube; + CUDD_VALUE_TYPE Value; + int nVars = dd->size; + int fFirstCube = 1; + int i; + + if ( F == NULL ) + { + printf("NULL"); + return; + } + if ( F == b0 ) + { + printf("Constant 0"); + return; + } + if ( F == b1 ) + { + printf("Constant 1"); + return; + } + + Cudd_ForeachCube( dd, F, Gen, Cube, Value ) + { + if ( fFirstCube ) + fFirstCube = 0; + else +// Output << " + "; + printf( " + " ); + + for ( i = 0; i < nVars; i++ ) + if ( Cube[i] == 0 ) + printf( "[%d]'", i ); +// printf( "%c'", (char)('a'+i) ); + else if ( Cube[i] == 1 ) + printf( "[%d]", i ); +// printf( "%c", (char)('a'+i) ); + } + +// printf("\n"); +} +/**Function******************************************************************** + + Synopsis [Returns the size of the support.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +int Extra_bddSuppSize( DdManager * dd, DdNode * bSupp ) +{ + int Counter = 0; + while ( bSupp != b1 ) + { + assert( !Cudd_IsComplement(bSupp) ); + assert( cuddE(bSupp) == b0 ); + + bSupp = cuddT(bSupp); + Counter++; + } + return Counter; +} + +/**Function******************************************************************** + + Synopsis [Returns 1 if the support contains the given BDD variable.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +int Extra_bddSuppContainVar( DdManager * dd, DdNode * bS, DdNode * bVar ) +{ + for( ; bS != b1; bS = cuddT(bS) ) + if ( bS->index == bVar->index ) + return 1; + return 0; +} + +/**Function******************************************************************** + + Synopsis [Returns 1 if two supports represented as BDD cubes are overlapping.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +int Extra_bddSuppOverlapping( DdManager * dd, DdNode * S1, DdNode * S2 ) +{ + while ( S1->index != CUDD_CONST_INDEX && S2->index != CUDD_CONST_INDEX ) + { + // if the top vars are the same, they intersect + if ( S1->index == S2->index ) + return 1; + // if the top vars are different, skip the one, which is higher + if ( dd->perm[S1->index] < dd->perm[S2->index] ) + S1 = cuddT(S1); + else + S2 = cuddT(S2); + } + return 0; +} + +/**Function******************************************************************** + + Synopsis [Returns the number of different vars in two supports.] + + Description [Counts the number of variables that appear in one support and + does not appear in other support. If the number exceeds DiffMax, returns DiffMax.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +int Extra_bddSuppDifferentVars( DdManager * dd, DdNode * S1, DdNode * S2, int DiffMax ) +{ + int Result = 0; + while ( S1->index != CUDD_CONST_INDEX && S2->index != CUDD_CONST_INDEX ) + { + // if the top vars are the same, this var is the same + if ( S1->index == S2->index ) + { + S1 = cuddT(S1); + S2 = cuddT(S2); + continue; + } + // the top var is different + Result++; + + if ( Result >= DiffMax ) + return DiffMax; + + // if the top vars are different, skip the one, which is higher + if ( dd->perm[S1->index] < dd->perm[S2->index] ) + S1 = cuddT(S1); + else + S2 = cuddT(S2); + } + + // consider the remaining variables + if ( S1->index != CUDD_CONST_INDEX ) + Result += Extra_bddSuppSize(dd,S1); + else if ( S2->index != CUDD_CONST_INDEX ) + Result += Extra_bddSuppSize(dd,S2); + + if ( Result >= DiffMax ) + return DiffMax; + return Result; +} + + +/**Function******************************************************************** + + Synopsis [Checks the support containment.] + + Description [This function returns 1 if one support is contained in another. + In this case, bLarge (bSmall) is assigned to point to the larger (smaller) support. + If the supports are identical, return 0 and does not assign the supports!] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +int Extra_bddSuppCheckContainment( DdManager * dd, DdNode * bL, DdNode * bH, DdNode ** bLarge, DdNode ** bSmall ) +{ + DdNode * bSL = bL; + DdNode * bSH = bH; + int fLcontainsH = 1; + int fHcontainsL = 1; + int TopVar; + + if ( bSL == bSH ) + return 0; + + while ( bSL != b1 || bSH != b1 ) + { + if ( bSL == b1 ) + { // Low component has no vars; High components has some vars + fLcontainsH = 0; + if ( fHcontainsL == 0 ) + return 0; + else + break; + } + + if ( bSH == b1 ) + { // similarly + fHcontainsL = 0; + if ( fLcontainsH == 0 ) + return 0; + else + break; + } + + // determine the topmost var of the supports by comparing their levels + if ( dd->perm[bSL->index] < dd->perm[bSH->index] ) + TopVar = bSL->index; + else + TopVar = bSH->index; + + if ( TopVar == bSL->index && TopVar == bSH->index ) + { // they are on the same level + // it does not tell us anything about their containment + // skip this var + bSL = cuddT(bSL); + bSH = cuddT(bSH); + } + else if ( TopVar == bSL->index ) // and TopVar != bSH->index + { // Low components is higher and contains more vars + // it is not possible that High component contains Low + fHcontainsL = 0; + // skip this var + bSL = cuddT(bSL); + } + else // if ( TopVar == bSH->index ) // and TopVar != bSL->index + { // similarly + fLcontainsH = 0; + // skip this var + bSH = cuddT(bSH); + } + + // check the stopping condition + if ( !fHcontainsL && !fLcontainsH ) + return 0; + } + // only one of them can be true at the same time + assert( !fHcontainsL || !fLcontainsH ); + if ( fHcontainsL ) + { + *bLarge = bH; + *bSmall = bL; + } + else // fLcontainsH + { + *bLarge = bL; + *bSmall = bH; + } + return 1; +} + + +/**Function******************************************************************** + + Synopsis [Finds variables on which the DD depends and returns them as am array.] + + Description [Finds the variables on which the DD depends. Returns an array + with entries set to 1 for those variables that belong to the support; + NULL otherwise. The array is allocated by the user and should have at least + as many entries as the maximum number of variables in BDD and ZDD parts of + the manager.] + + SideEffects [None] + + SeeAlso [Cudd_Support Cudd_VectorSupport Cudd_ClassifySupport] + +******************************************************************************/ +int * +Extra_SupportArray( + DdManager * dd, /* manager */ + DdNode * f, /* DD whose support is sought */ + int * support ) /* array allocated by the user */ +{ + int i, size; + + /* Initialize support array for ddSupportStep. */ + size = ddMax(dd->size, dd->sizeZ); + for (i = 0; i < size; i++) + support[i] = 0; + + /* Compute support and clean up markers. */ + ddSupportStep(Cudd_Regular(f),support); + ddClearFlag(Cudd_Regular(f)); + + return(support); + +} /* end of Extra_SupportArray */ + +/**Function******************************************************************** + + Synopsis [Finds the variables on which a set of DDs depends.] + + Description [Finds the variables on which a set of DDs depends. + The set must contain either BDDs and ADDs, or ZDDs. + Returns a BDD consisting of the product of the variables if + successful; NULL otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_Support Cudd_ClassifySupport] + +******************************************************************************/ +int * +Extra_VectorSupportArray( + DdManager * dd, /* manager */ + DdNode ** F, /* array of DDs whose support is sought */ + int n, /* size of the array */ + int * support ) /* array allocated by the user */ +{ + int i, size; + + /* Allocate and initialize support array for ddSupportStep. */ + size = ddMax( dd->size, dd->sizeZ ); + for ( i = 0; i < size; i++ ) + support[i] = 0; + + /* Compute support and clean up markers. */ + for ( i = 0; i < n; i++ ) + ddSupportStep( Cudd_Regular(F[i]), support ); + for ( i = 0; i < n; i++ ) + ddClearFlag( Cudd_Regular(F[i]) ); + + return support; +} + +/**Function******************************************************************** + + Synopsis [Find any cube belonging to the on-set of the function.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_bddFindOneCube( DdManager * dd, DdNode * bF ) +{ + char * s_Temp; + DdNode * bCube, * bTemp; + int v; + + // get the vector of variables in the cube + s_Temp = ALLOC( char, dd->size ); + Cudd_bddPickOneCube( dd, bF, s_Temp ); + + // start the cube + bCube = b1; Cudd_Ref( bCube ); + for ( v = 0; v < dd->size; v++ ) + if ( s_Temp[v] == 0 ) + { +// Cube &= !s_XVars[v]; + bCube = Cudd_bddAnd( dd, bTemp = bCube, Cudd_Not(dd->vars[v]) ); Cudd_Ref( bCube ); + Cudd_RecursiveDeref( dd, bTemp ); + } + else if ( s_Temp[v] == 1 ) + { +// Cube &= s_XVars[v]; + bCube = Cudd_bddAnd( dd, bTemp = bCube, dd->vars[v] ); Cudd_Ref( bCube ); + Cudd_RecursiveDeref( dd, bTemp ); + } + Cudd_Deref(bCube); + free( s_Temp ); + return bCube; +} + +/**Function******************************************************************** + + Synopsis [Returns one cube contained in the given BDD.] + + Description [This function returns the cube with the smallest + bits-to-integer value.] + + SideEffects [] + +******************************************************************************/ +DdNode * Extra_bddGetOneCube( DdManager * dd, DdNode * bFunc ) +{ + DdNode * bFuncR, * bFunc0, * bFunc1; + DdNode * bRes0, * bRes1, * bRes; + + bFuncR = Cudd_Regular(bFunc); + if ( cuddIsConstant(bFuncR) ) + return bFunc; + + // cofactor + if ( Cudd_IsComplement(bFunc) ) + { + bFunc0 = Cudd_Not( cuddE(bFuncR) ); + bFunc1 = Cudd_Not( cuddT(bFuncR) ); + } + else + { + bFunc0 = cuddE(bFuncR); + bFunc1 = cuddT(bFuncR); + } + + // try to find the cube with the negative literal + bRes0 = Extra_bddGetOneCube( dd, bFunc0 ); Cudd_Ref( bRes0 ); + + if ( bRes0 != b0 ) + { + bRes = Cudd_bddAnd( dd, bRes0, Cudd_Not(dd->vars[bFuncR->index]) ); Cudd_Ref( bRes ); + Cudd_RecursiveDeref( dd, bRes0 ); + } + else + { + Cudd_RecursiveDeref( dd, bRes0 ); + // try to find the cube with the positive literal + bRes1 = Extra_bddGetOneCube( dd, bFunc1 ); Cudd_Ref( bRes1 ); + assert( bRes1 != b0 ); + bRes = Cudd_bddAnd( dd, bRes1, dd->vars[bFuncR->index] ); Cudd_Ref( bRes ); + Cudd_RecursiveDeref( dd, bRes1 ); + } + + Cudd_Deref( bRes ); + return bRes; +} + +/**Function******************************************************************** + + Synopsis [Performs the reordering-sensitive step of Extra_bddMove().] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_bddComputeRangeCube( DdManager * dd, int iStart, int iStop ) +{ + DdNode * bTemp, * bProd; + int i; + assert( iStart <= iStop ); + assert( iStart >= 0 && iStart <= dd->size ); + assert( iStop >= 0 && iStop <= dd->size ); + bProd = b1; Cudd_Ref( bProd ); + for ( i = iStart; i < iStop; i++ ) + { + bProd = Cudd_bddAnd( dd, bTemp = bProd, dd->vars[i] ); Cudd_Ref( bProd ); + Cudd_RecursiveDeref( dd, bTemp ); + } + Cudd_Deref( bProd ); + return bProd; +} + +/**Function******************************************************************** + + Synopsis [Computes the cube of BDD variables corresponding to bits it the bit-code] + + Description [Returns a bdd composed of elementary bdds found in array BddVars[] such + that the bdd vars encode the number Value of bit length CodeWidth (if fMsbFirst is 1, + the most significant bit is encoded with the first bdd variable). If the variables + BddVars are not specified, takes the first CodeWidth variables of the manager] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_bddBitsToCube( DdManager * dd, int Code, int CodeWidth, DdNode ** pbVars, int fMsbFirst ) +{ + int z; + DdNode * bTemp, * bVar, * bVarBdd, * bResult; + + bResult = b1; Cudd_Ref( bResult ); + for ( z = 0; z < CodeWidth; z++ ) + { + bVarBdd = (pbVars)? pbVars[z]: dd->vars[z]; + if ( fMsbFirst ) + bVar = Cudd_NotCond( bVarBdd, (Code & (1 << (CodeWidth-1-z)))==0 ); + else + bVar = Cudd_NotCond( bVarBdd, (Code & (1 << (z)))==0 ); + bResult = Cudd_bddAnd( dd, bTemp = bResult, bVar ); Cudd_Ref( bResult ); + Cudd_RecursiveDeref( dd, bTemp ); + } + Cudd_Deref( bResult ); + + return bResult; +} /* end of Extra_bddBitsToCube */ + +/**Function******************************************************************** + + Synopsis [Finds the support as a negative polarity cube.] + + Description [Finds the variables on which a DD depends. Returns a BDD + consisting of the product of the variables in the negative polarity + if successful; NULL otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_VectorSupport Cudd_Support] + +******************************************************************************/ +DdNode * Extra_bddSupportNegativeCube( DdManager * dd, DdNode * f ) +{ + int *support; + DdNode *res, *tmp, *var; + int i, j; + int size; + + /* Allocate and initialize support array for ddSupportStep. */ + size = ddMax( dd->size, dd->sizeZ ); + support = ALLOC( int, size ); + if ( support == NULL ) + { + dd->errorCode = CUDD_MEMORY_OUT; + return ( NULL ); + } + for ( i = 0; i < size; i++ ) + { + support[i] = 0; + } + + /* Compute support and clean up markers. */ + ddSupportStep( Cudd_Regular( f ), support ); + ddClearFlag( Cudd_Regular( f ) ); + + /* Transform support from array to cube. */ + do + { + dd->reordered = 0; + res = DD_ONE( dd ); + cuddRef( res ); + for ( j = size - 1; j >= 0; j-- ) + { /* for each level bottom-up */ + i = ( j >= dd->size ) ? j : dd->invperm[j]; + if ( support[i] == 1 ) + { + var = cuddUniqueInter( dd, i, dd->one, Cudd_Not( dd->one ) ); + ////////////////////////////////////////////////////////////////// + var = Cudd_Not(var); + ////////////////////////////////////////////////////////////////// + cuddRef( var ); + tmp = cuddBddAndRecur( dd, res, var ); + if ( tmp == NULL ) + { + Cudd_RecursiveDeref( dd, res ); + Cudd_RecursiveDeref( dd, var ); + res = NULL; + break; + } + cuddRef( tmp ); + Cudd_RecursiveDeref( dd, res ); + Cudd_RecursiveDeref( dd, var ); + res = tmp; + } + } + } + while ( dd->reordered == 1 ); + + FREE( support ); + if ( res != NULL ) + cuddDeref( res ); + return ( res ); + +} /* end of Extra_SupportNeg */ + +/**Function******************************************************************** + + Synopsis [Returns 1 if the BDD is the BDD of elementary variable.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +int Extra_bddIsVar( DdNode * bFunc ) +{ + bFunc = Cudd_Regular( bFunc ); + if ( cuddIsConstant(bFunc) ) + return 0; + return cuddIsConstant( cuddT(bFunc) ) && cuddIsConstant( Cudd_Regular(cuddE(bFunc)) ); +} + +/**Function******************************************************************** + + Synopsis [Creates AND composed of the first nVars of the manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_bddCreateAnd( DdManager * dd, int nVars ) +{ + DdNode * bFunc, * bTemp; + int i; + bFunc = Cudd_ReadOne(dd); Cudd_Ref( bFunc ); + for ( i = 0; i < nVars; i++ ) + { + bFunc = Cudd_bddAnd( dd, bTemp = bFunc, Cudd_bddIthVar(dd,i) ); Cudd_Ref( bFunc ); + Cudd_RecursiveDeref( dd, bTemp ); + } + Cudd_Deref( bFunc ); + return bFunc; +} + +/**Function******************************************************************** + + Synopsis [Creates OR composed of the first nVars of the manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_bddCreateOr( DdManager * dd, int nVars ) +{ + DdNode * bFunc, * bTemp; + int i; + bFunc = Cudd_ReadLogicZero(dd); Cudd_Ref( bFunc ); + for ( i = 0; i < nVars; i++ ) + { + bFunc = Cudd_bddOr( dd, bTemp = bFunc, Cudd_bddIthVar(dd,i) ); Cudd_Ref( bFunc ); + Cudd_RecursiveDeref( dd, bTemp ); + } + Cudd_Deref( bFunc ); + return bFunc; +} + +/**Function******************************************************************** + + Synopsis [Creates EXOR composed of the first nVars of the manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_bddCreateExor( DdManager * dd, int nVars ) +{ + DdNode * bFunc, * bTemp; + int i; + bFunc = Cudd_ReadLogicZero(dd); Cudd_Ref( bFunc ); + for ( i = 0; i < nVars; i++ ) + { + bFunc = Cudd_bddXor( dd, bTemp = bFunc, Cudd_bddIthVar(dd,i) ); Cudd_Ref( bFunc ); + Cudd_RecursiveDeref( dd, bTemp ); + } + Cudd_Deref( bFunc ); + return bFunc; +} + +/**Function******************************************************************** + + Synopsis [Computes the set of primes as a ZDD.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_zddPrimes( DdManager * dd, DdNode * F ) +{ + DdNode *res; + do { + dd->reordered = 0; + res = extraZddPrimes(dd, F); + if ( dd->reordered == 1 ) + printf("\nReordering in Extra_zddPrimes()\n"); + } while (dd->reordered == 1); + return(res); + +} /* end of Extra_zddPrimes */ + +/**Function******************************************************************** + + Synopsis [Permutes the variables of the array of BDDs.] + + Description [Given a permutation in array permut, creates a new BDD + with permuted variables. There should be an entry in array permut + for each variable in the manager. The i-th entry of permut holds the + index of the variable that is to substitute the i-th variable. + The DDs in the resulting array are already referenced.] + + SideEffects [None] + + SeeAlso [Cudd_addPermute Cudd_bddSwapVariables] + +******************************************************************************/ +void Extra_bddPermuteArray( DdManager * manager, DdNode ** bNodesIn, DdNode ** bNodesOut, int nNodes, int *permut ) +{ + DdHashTable *table; + int i, k; + do + { + manager->reordered = 0; + table = cuddHashTableInit( manager, 1, 2 ); + + /* permute the output functions one-by-one */ + for ( i = 0; i < nNodes; i++ ) + { + bNodesOut[i] = cuddBddPermuteRecur( manager, table, bNodesIn[i], permut ); + if ( bNodesOut[i] == NULL ) + { + /* deref the array of the already computed outputs */ + for ( k = 0; k < i; k++ ) + Cudd_RecursiveDeref( manager, bNodesOut[k] ); + break; + } + cuddRef( bNodesOut[i] ); + } + /* Dispose of local cache. */ + cuddHashTableQuit( table ); + } + while ( manager->reordered == 1 ); +} /* end of Extra_bddPermuteArray */ + + +/*---------------------------------------------------------------------------*/ +/* Definition of internal functions */ +/*---------------------------------------------------------------------------*/ + +/**Function******************************************************************** + + Synopsis [Performs the reordering-sensitive step of Extra_bddMove().] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * extraBddMove( + DdManager * dd, /* the DD manager */ + DdNode * bF, + DdNode * bDist) +{ + DdNode * bRes; + + if ( Cudd_IsConstant(bF) ) + return bF; + + if ( bRes = cuddCacheLookup2(dd, extraBddMove, bF, bDist) ) + return bRes; + else + { + DdNode * bRes0, * bRes1; + DdNode * bF0, * bF1; + DdNode * bFR = Cudd_Regular(bF); + int VarNew; + + if ( Cudd_IsComplement(bDist) ) + VarNew = bFR->index - Cudd_Not(bDist)->index; + else + VarNew = bFR->index + bDist->index; + assert( VarNew < dd->size ); + + // cofactor the functions + if ( bFR != bF ) // bFunc is complemented + { + bF0 = Cudd_Not( cuddE(bFR) ); + bF1 = Cudd_Not( cuddT(bFR) ); + } + else + { + bF0 = cuddE(bFR); + bF1 = cuddT(bFR); + } + + bRes0 = extraBddMove( dd, bF0, bDist ); + if ( bRes0 == NULL ) + return NULL; + cuddRef( bRes0 ); + + bRes1 = extraBddMove( dd, bF1, bDist ); + if ( bRes1 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + return NULL; + } + cuddRef( bRes1 ); + + /* only bRes0 and bRes1 are referenced at this point */ + bRes = cuddBddIteRecur( dd, dd->vars[VarNew], bRes1, bRes0 ); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + Cudd_RecursiveDeref( dd, bRes1 ); + return NULL; + } + cuddRef( bRes ); + Cudd_RecursiveDeref( dd, bRes0 ); + Cudd_RecursiveDeref( dd, bRes1 ); + + /* insert the result into cache */ + cuddCacheInsert2( dd, extraBddMove, bF, bDist, bRes ); + cuddDeref( bRes ); + return bRes; + } +} /* end of extraBddMove */ + + +/**Function******************************************************************** + + Synopsis [Finds three cofactors of the cover w.r.t. to the topmost variable.] + + Description [Finds three cofactors of the cover w.r.t. to the topmost variable. + Does not check the cover for being a constant. Assumes that ZDD variables encoding + positive and negative polarities are adjacent in the variable order. Is different + from cuddZddGetCofactors3() in that it does not compute the cofactors w.r.t. the + given variable but takes the cofactors with respent to the topmost variable. + This function is more efficient when used in recursive procedures because it does + not require referencing of the resulting cofactors (compare cuddZddProduct() + and extraZddPrimeProduct()).] + + SideEffects [None] + + SeeAlso [cuddZddGetCofactors3] + +******************************************************************************/ +void +extraDecomposeCover( + DdManager* dd, /* the manager */ + DdNode* zC, /* the cover */ + DdNode** zC0, /* the pointer to the negative var cofactor */ + DdNode** zC1, /* the pointer to the positive var cofactor */ + DdNode** zC2 ) /* the pointer to the cofactor without var */ +{ + if ( (zC->index & 1) == 0 ) + { /* the top variable is present in positive polarity and maybe in negative */ + + DdNode *Temp = cuddE( zC ); + *zC1 = cuddT( zC ); + if ( cuddIZ(dd,Temp->index) == cuddIZ(dd,zC->index) + 1 ) + { /* Temp is not a terminal node + * top var is present in negative polarity */ + *zC2 = cuddE( Temp ); + *zC0 = cuddT( Temp ); + } + else + { /* top var is not present in negative polarity */ + *zC2 = Temp; + *zC0 = dd->zero; + } + } + else + { /* the top variable is present only in negative */ + *zC1 = dd->zero; + *zC2 = cuddE( zC ); + *zC0 = cuddT( zC ); + } +} /* extraDecomposeCover */ + +/*---------------------------------------------------------------------------*/ +/* Definition of static Functions */ +/*---------------------------------------------------------------------------*/ + +/**Function******************************************************************** + + Synopsis [Convert a BDD from a manager to another one.] + + Description [Convert a BDD from a manager to another one. Returns a + pointer to the BDD in the destination manager if successful; NULL + otherwise.] + + SideEffects [None] + + SeeAlso [Extra_TransferPermute] + +******************************************************************************/ +DdNode * extraTransferPermute( DdManager * ddS, DdManager * ddD, DdNode * f, int * Permute ) +{ + DdNode *res; + st_table *table = NULL; + st_generator *gen = NULL; + DdNode *key, *value; + + table = st_init_table( st_ptrcmp, st_ptrhash ); + if ( table == NULL ) + goto failure; + res = extraTransferPermuteRecur( ddS, ddD, f, table, Permute ); + if ( res != NULL ) + cuddRef( res ); + + /* Dereference all elements in the table and dispose of the table. + ** This must be done also if res is NULL to avoid leaks in case of + ** reordering. */ + gen = st_init_gen( table ); + if ( gen == NULL ) + goto failure; + while ( st_gen( gen, ( char ** ) &key, ( char ** ) &value ) ) + { + Cudd_RecursiveDeref( ddD, value ); + } + st_free_gen( gen ); + gen = NULL; + st_free_table( table ); + table = NULL; + + if ( res != NULL ) + cuddDeref( res ); + return ( res ); + + failure: + if ( table != NULL ) + st_free_table( table ); + if ( gen != NULL ) + st_free_gen( gen ); + return ( NULL ); + +} /* end of extraTransferPermute */ + + +/**Function******************************************************************** + + Synopsis [Performs the recursive step of Extra_TransferPermute.] + + Description [Performs the recursive step of Extra_TransferPermute. + Returns a pointer to the result if successful; NULL otherwise.] + + SideEffects [None] + + SeeAlso [extraTransferPermute] + +******************************************************************************/ +static DdNode * +extraTransferPermuteRecur( + DdManager * ddS, + DdManager * ddD, + DdNode * f, + st_table * table, + int * Permute ) +{ + DdNode *ft, *fe, *t, *e, *var, *res; + DdNode *one, *zero; + int index; + int comple = 0; + + statLine( ddD ); + one = DD_ONE( ddD ); + comple = Cudd_IsComplement( f ); + + /* Trivial cases. */ + if ( Cudd_IsConstant( f ) ) + return ( Cudd_NotCond( one, comple ) ); + + + /* Make canonical to increase the utilization of the cache. */ + f = Cudd_NotCond( f, comple ); + /* Now f is a regular pointer to a non-constant node. */ + + /* Check the cache. */ + if ( st_lookup( table, ( char * ) f, ( char ** ) &res ) ) + return ( Cudd_NotCond( res, comple ) ); + + /* Recursive step. */ + if ( Permute ) + index = Permute[f->index]; + else + index = f->index; + + ft = cuddT( f ); + fe = cuddE( f ); + + t = extraTransferPermuteRecur( ddS, ddD, ft, table, Permute ); + if ( t == NULL ) + { + return ( NULL ); + } + cuddRef( t ); + + e = extraTransferPermuteRecur( ddS, ddD, fe, table, Permute ); + if ( e == NULL ) + { + Cudd_RecursiveDeref( ddD, t ); + return ( NULL ); + } + cuddRef( e ); + + zero = Cudd_Not(ddD->one); + var = cuddUniqueInter( ddD, index, one, zero ); + if ( var == NULL ) + { + Cudd_RecursiveDeref( ddD, t ); + Cudd_RecursiveDeref( ddD, e ); + return ( NULL ); + } + res = cuddBddIteRecur( ddD, var, t, e ); + + if ( res == NULL ) + { + Cudd_RecursiveDeref( ddD, t ); + Cudd_RecursiveDeref( ddD, e ); + return ( NULL ); + } + cuddRef( res ); + Cudd_RecursiveDeref( ddD, t ); + Cudd_RecursiveDeref( ddD, e ); + + if ( st_add_direct( table, ( char * ) f, ( char * ) res ) == + ST_OUT_OF_MEM ) + { + Cudd_RecursiveDeref( ddD, res ); + return ( NULL ); + } + return ( Cudd_NotCond( res, comple ) ); + +} /* end of extraTransferPermuteRecur */ + +/**Function******************************************************************** + + Synopsis [Performs the recursive step of Cudd_Support.] + + Description [Performs the recursive step of Cudd_Support. Performs a + DFS from f. The support is accumulated in supp as a side effect. Uses + the LSB of the then pointer as visited flag.] + + SideEffects [None] + + SeeAlso [ddClearFlag] + +******************************************************************************/ +static void +ddSupportStep( + DdNode * f, + int * support) +{ + if (cuddIsConstant(f) || Cudd_IsComplement(f->next)) { + return; + } + + support[f->index] = 1; + ddSupportStep(cuddT(f),support); + ddSupportStep(Cudd_Regular(cuddE(f)),support); + /* Mark as visited. */ + f->next = Cudd_Not(f->next); + return; + +} /* end of ddSupportStep */ + + +/**Function******************************************************************** + + Synopsis [Performs a DFS from f, clearing the LSB of the next + pointers.] + + Description [] + + SideEffects [None] + + SeeAlso [ddSupportStep ddDagInt] + +******************************************************************************/ +static void +ddClearFlag( + DdNode * f) +{ + if (!Cudd_IsComplement(f->next)) { + return; + } + /* Clear visited flag. */ + f->next = Cudd_Regular(f->next); + if (cuddIsConstant(f)) { + return; + } + ddClearFlag(cuddT(f)); + ddClearFlag(Cudd_Regular(cuddE(f))); + return; + +} /* end of ddClearFlag */ + + +/**Function******************************************************************** + + Synopsis [Composed three subcovers into one ZDD.] + + Description [] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +DdNode * +extraComposeCover( + DdManager* dd, /* the manager */ + DdNode* zC0, /* the pointer to the negative var cofactor */ + DdNode* zC1, /* the pointer to the positive var cofactor */ + DdNode* zC2, /* the pointer to the cofactor without var */ + int TopVar) /* the index of the positive ZDD var */ +{ + DdNode * zRes, * zTemp; + /* compose with-neg-var and without-var using the neg ZDD var */ + zTemp = cuddZddGetNode( dd, 2*TopVar + 1, zC0, zC2 ); + if ( zTemp == NULL ) + { + Cudd_RecursiveDerefZdd(dd, zC0); + Cudd_RecursiveDerefZdd(dd, zC1); + Cudd_RecursiveDerefZdd(dd, zC2); + return NULL; + } + cuddRef( zTemp ); + cuddDeref( zC0 ); + cuddDeref( zC2 ); + + /* compose with-pos-var and previous result using the pos ZDD var */ + zRes = cuddZddGetNode( dd, 2*TopVar, zC1, zTemp ); + if ( zRes == NULL ) + { + Cudd_RecursiveDerefZdd(dd, zC1); + Cudd_RecursiveDerefZdd(dd, zTemp); + return NULL; + } + cuddDeref( zC1 ); + cuddDeref( zTemp ); + return zRes; +} /* extraComposeCover */ + +/**Function******************************************************************** + + Synopsis [Performs the recursive step of prime computation.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode* extraZddPrimes( DdManager *dd, DdNode* F ) +{ + DdNode *zRes; + + if ( F == Cudd_Not( dd->one ) ) + return dd->zero; + if ( F == dd->one ) + return dd->one; + + /* check cache */ + zRes = cuddCacheLookup1Zdd(dd, extraZddPrimes, F); + if (zRes) + return(zRes); + { + /* temporary variables */ + DdNode *bF01, *zP0, *zP1; + /* three components of the prime set */ + DdNode *zResE, *zResP, *zResN; + int fIsComp = Cudd_IsComplement( F ); + + /* find cofactors of F */ + DdNode * bF0 = Cudd_NotCond( Cudd_E( F ), fIsComp ); + DdNode * bF1 = Cudd_NotCond( Cudd_T( F ), fIsComp ); + + /* find the intersection of cofactors */ + bF01 = cuddBddAndRecur( dd, bF0, bF1 ); + if ( bF01 == NULL ) return NULL; + cuddRef( bF01 ); + + /* solve the problems for cofactors */ + zP0 = extraZddPrimes( dd, bF0 ); + if ( zP0 == NULL ) + { + Cudd_RecursiveDeref( dd, bF01 ); + return NULL; + } + cuddRef( zP0 ); + + zP1 = extraZddPrimes( dd, bF1 ); + if ( zP1 == NULL ) + { + Cudd_RecursiveDeref( dd, bF01 ); + Cudd_RecursiveDerefZdd( dd, zP0 ); + return NULL; + } + cuddRef( zP1 ); + + /* check for local unateness */ + if ( bF01 == bF0 ) /* unate increasing */ + { + /* intersection is useless */ + cuddDeref( bF01 ); + /* the primes of intersection are the primes of F0 */ + zResE = zP0; + /* there are no primes with negative var */ + zResN = dd->zero; + cuddRef( zResN ); + /* primes with positive var are primes of F1 that are not primes of F01 */ + zResP = cuddZddDiff( dd, zP1, zP0 ); + if ( zResP == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zResE ); + Cudd_RecursiveDerefZdd( dd, zResN ); + Cudd_RecursiveDerefZdd( dd, zP1 ); + return NULL; + } + cuddRef( zResP ); + Cudd_RecursiveDerefZdd( dd, zP1 ); + } + else if ( bF01 == bF1 ) /* unate decreasing */ + { + /* intersection is useless */ + cuddDeref( bF01 ); + /* the primes of intersection are the primes of F1 */ + zResE = zP1; + /* there are no primes with positive var */ + zResP = dd->zero; + cuddRef( zResP ); + /* primes with negative var are primes of F0 that are not primes of F01 */ + zResN = cuddZddDiff( dd, zP0, zP1 ); + if ( zResN == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zResE ); + Cudd_RecursiveDerefZdd( dd, zResP ); + Cudd_RecursiveDerefZdd( dd, zP0 ); + return NULL; + } + cuddRef( zResN ); + Cudd_RecursiveDerefZdd( dd, zP0 ); + } + else /* not unate */ + { + /* primes without the top var are primes of F10 */ + zResE = extraZddPrimes( dd, bF01 ); + if ( zResE == NULL ) + { + Cudd_RecursiveDerefZdd( dd, bF01 ); + Cudd_RecursiveDerefZdd( dd, zP0 ); + Cudd_RecursiveDerefZdd( dd, zP1 ); + return NULL; + } + cuddRef( zResE ); + Cudd_RecursiveDeref( dd, bF01 ); + + /* primes with the negative top var are those of P0 that are not in F10 */ + zResN = cuddZddDiff( dd, zP0, zResE ); + if ( zResN == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zResE ); + Cudd_RecursiveDerefZdd( dd, zP0 ); + Cudd_RecursiveDerefZdd( dd, zP1 ); + return NULL; + } + cuddRef( zResN ); + Cudd_RecursiveDerefZdd( dd, zP0 ); + + /* primes with the positive top var are those of P1 that are not in F10 */ + zResP = cuddZddDiff( dd, zP1, zResE ); + if ( zResP == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zResE ); + Cudd_RecursiveDerefZdd( dd, zResN ); + Cudd_RecursiveDerefZdd( dd, zP1 ); + return NULL; + } + cuddRef( zResP ); + Cudd_RecursiveDerefZdd( dd, zP1 ); + } + + zRes = extraComposeCover( dd, zResN, zResP, zResE, Cudd_Regular(F)->index ); + if ( zRes == NULL ) return NULL; + + /* insert the result into cache */ + cuddCacheInsert1(dd, extraZddPrimes, F, zRes); + return zRes; + } +} /* end of extraZddPrimes */ + +/**Function******************************************************************** + + Synopsis [Implements the recursive step of Cudd_bddPermute.] + + Description [ Recursively puts the BDD in the order given in the array permut. + Checks for trivial cases to terminate recursion, then splits on the + children of this node. Once the solutions for the children are + obtained, it puts into the current position the node from the rest of + the BDD that should be here. Then returns this BDD. + The key here is that the node being visited is NOT put in its proper + place by this instance, but rather is switched when its proper position + is reached in the recursion tree.

+ The DdNode * that is returned is the same BDD as passed in as node, + but in the new order.] + + SideEffects [None] + + SeeAlso [Cudd_bddPermute cuddAddPermuteRecur] + +******************************************************************************/ +static DdNode * +cuddBddPermuteRecur( DdManager * manager /* DD manager */ , + DdHashTable * table /* computed table */ , + DdNode * node /* BDD to be reordered */ , + int *permut /* permutation array */ ) +{ + DdNode *N, *T, *E; + DdNode *res; + int index; + + statLine( manager ); + N = Cudd_Regular( node ); + + /* Check for terminal case of constant node. */ + if ( cuddIsConstant( N ) ) + { + return ( node ); + } + + /* If problem already solved, look up answer and return. */ + if ( N->ref != 1 && ( res = cuddHashTableLookup1( table, N ) ) != NULL ) + { +#ifdef DD_DEBUG + bddPermuteRecurHits++; +#endif + return ( Cudd_NotCond( res, N != node ) ); + } + + /* Split and recur on children of this node. */ + T = cuddBddPermuteRecur( manager, table, cuddT( N ), permut ); + if ( T == NULL ) + return ( NULL ); + cuddRef( T ); + E = cuddBddPermuteRecur( manager, table, cuddE( N ), permut ); + if ( E == NULL ) + { + Cudd_IterDerefBdd( manager, T ); + return ( NULL ); + } + cuddRef( E ); + + /* Move variable that should be in this position to this position + ** by retrieving the single var BDD for that variable, and calling + ** cuddBddIteRecur with the T and E we just created. + */ + index = permut[N->index]; + res = cuddBddIteRecur( manager, manager->vars[index], T, E ); + if ( res == NULL ) + { + Cudd_IterDerefBdd( manager, T ); + Cudd_IterDerefBdd( manager, E ); + return ( NULL ); + } + cuddRef( res ); + Cudd_IterDerefBdd( manager, T ); + Cudd_IterDerefBdd( manager, E ); + + /* Do not keep the result if the reference count is only 1, since + ** it will not be visited again. + */ + if ( N->ref != 1 ) + { + ptrint fanout = ( ptrint ) N->ref; + cuddSatDec( fanout ); + if ( !cuddHashTableInsert1( table, N, res, fanout ) ) + { + Cudd_IterDerefBdd( manager, res ); + return ( NULL ); + } + } + cuddDeref( res ); + return ( Cudd_NotCond( res, N != node ) ); + +} /* end of cuddBddPermuteRecur */ + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/misc/extra/extraBddSymm.c b/src/misc/extra/extraBddSymm.c new file mode 100644 index 00000000..358402b0 --- /dev/null +++ b/src/misc/extra/extraBddSymm.c @@ -0,0 +1,1469 @@ +/**CFile**************************************************************** + + FileName [extraBddSymm.c] + + PackageName [extra] + + Synopsis [Efficient methods to compute the information about + symmetric variables using the algorithm presented in the paper: + A. Mishchenko. Fast Computation of Symmetries in Boolean Functions. + Transactions on CAD, Nov. 2003.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 2.0. Started - September 1, 2003.] + + Revision [$Id: extraBddSymm.c,v 1.0 2003/09/01 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "extra.h" + +/*---------------------------------------------------------------------------*/ +/* Constant declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Stucture declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Type declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Variable declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Macro declarations */ +/*---------------------------------------------------------------------------*/ + +#define DD_GET_SYMM_VARS_TAG 0x0a /* former DD_BDD_XOR_EXIST_ABSTRACT_TAG */ + +/**AutomaticStart*************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Static function prototypes */ +/*---------------------------------------------------------------------------*/ + +/**AutomaticEnd***************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Definition of exported functions */ +/*---------------------------------------------------------------------------*/ + +/**Function******************************************************************** + + Synopsis [Computes the classical symmetry information for the function.] + + Description [Returns the symmetry information in the form of Extra_SymmInfo_t structure.] + + SideEffects [If the ZDD variables are not derived from BDD variables with + multiplicity 2, this function may derive them in a wrong way.] + + SeeAlso [] + +******************************************************************************/ +Extra_SymmInfo_t * Extra_SymmPairsCompute( + DdManager * dd, /* the manager */ + DdNode * bFunc) /* the function whose symmetries are computed */ +{ + DdNode * bSupp; + DdNode * zRes; + Extra_SymmInfo_t * p; + + bSupp = Cudd_Support( dd, bFunc ); Cudd_Ref( bSupp ); + zRes = Extra_zddSymmPairsCompute( dd, bFunc, bSupp ); Cudd_Ref( zRes ); + + p = Extra_SymmPairsCreateFromZdd( dd, zRes, bSupp ); + + Cudd_RecursiveDeref( dd, bSupp ); + Cudd_RecursiveDerefZdd( dd, zRes ); + + return p; + +} /* end of Extra_SymmPairsCompute */ + + +/**Function******************************************************************** + + Synopsis [Computes the classical symmetry information as a ZDD.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_zddSymmPairsCompute( + DdManager * dd, /* the DD manager */ + DdNode * bF, + DdNode * bVars) +{ + DdNode * res; + do { + dd->reordered = 0; + res = extraZddSymmPairsCompute( dd, bF, bVars ); + } while (dd->reordered == 1); + return(res); + +} /* end of Extra_zddSymmPairsCompute */ + +/**Function******************************************************************** + + Synopsis [Returns a singleton-set ZDD containing all variables that are symmetric with the given one.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_zddGetSymmetricVars( + DdManager * dd, /* the DD manager */ + DdNode * bF, /* the first function - originally, the positive cofactor */ + DdNode * bG, /* the second fucntion - originally, the negative cofactor */ + DdNode * bVars) /* the set of variables, on which F and G depend */ +{ + DdNode * res; + do { + dd->reordered = 0; + res = extraZddGetSymmetricVars( dd, bF, bG, bVars ); + } while (dd->reordered == 1); + return(res); + +} /* end of Extra_zddGetSymmetricVars */ + + +/**Function******************************************************************** + + Synopsis [Converts a set of variables into a set of singleton subsets.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_zddGetSingletons( + DdManager * dd, /* the DD manager */ + DdNode * bVars) /* the set of variables */ +{ + DdNode * res; + do { + dd->reordered = 0; + res = extraZddGetSingletons( dd, bVars ); + } while (dd->reordered == 1); + return(res); + +} /* end of Extra_zddGetSingletons */ + +/**Function******************************************************************** + + Synopsis [Filters the set of variables using the support of the function.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_bddReduceVarSet( + DdManager * dd, /* the DD manager */ + DdNode * bVars, /* the set of variables to be reduced */ + DdNode * bF) /* the function whose support is used for reduction */ +{ + DdNode * res; + do { + dd->reordered = 0; + res = extraBddReduceVarSet( dd, bVars, bF ); + } while (dd->reordered == 1); + return(res); + +} /* end of Extra_bddReduceVarSet */ + + +/**Function******************************************************************** + + Synopsis [Allocates symmetry information structure.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +Extra_SymmInfo_t * Extra_SymmPairsAllocate( int nVars ) +{ + int i; + Extra_SymmInfo_t * p; + + // allocate and clean the storage for symmetry info + p = ALLOC( Extra_SymmInfo_t, 1 ); + memset( p, 0, sizeof(Extra_SymmInfo_t) ); + p->nVars = nVars; + p->pVars = ALLOC( int, nVars ); + p->pSymms = ALLOC( char *, nVars ); + p->pSymms[0] = ALLOC( char , nVars * nVars ); + memset( p->pSymms[0], 0, nVars * nVars * sizeof(char) ); + + for ( i = 1; i < nVars; i++ ) + p->pSymms[i] = p->pSymms[i-1] + nVars; + + return p; +} /* end of Extra_SymmPairsAllocate */ + +/**Function******************************************************************** + + Synopsis [Deallocates symmetry information structure.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +void Extra_SymmPairsDissolve( Extra_SymmInfo_t * p ) +{ + free( p->pVars ); + free( p->pSymms[0] ); + free( p->pSymms ); + free( p ); +} /* end of Extra_SymmPairsDissolve */ + +/**Function******************************************************************** + + Synopsis [Allocates symmetry information structure.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +void Extra_SymmPairsPrint( Extra_SymmInfo_t * p ) +{ + int i, k; + printf( "\n" ); + for ( i = 0; i < p->nVars; i++ ) + { + for ( k = 0; k <= i; k++ ) + printf( " " ); + for ( k = i+1; k < p->nVars; k++ ) + if ( p->pSymms[i][k] ) + printf( "1" ); + else + printf( "." ); + printf( "\n" ); + } +} /* end of Extra_SymmPairsPrint */ + + +/**Function******************************************************************** + + Synopsis [Creates the symmetry information structure from ZDD.] + + Description [ZDD representation of symmetries is the set of cubes, each + of which has two variables in the positive polarity. These variables correspond + to the symmetric variable pair.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +Extra_SymmInfo_t * Extra_SymmPairsCreateFromZdd( DdManager * dd, DdNode * zPairs, DdNode * bSupp ) +{ + int i; + int nSuppSize; + Extra_SymmInfo_t * p; + int * pMapVars2Nums; + DdNode * bTemp; + DdNode * zSet, * zCube, * zTemp; + int iVar1, iVar2; + + nSuppSize = Extra_bddSuppSize( dd, bSupp ); + + // allocate and clean the storage for symmetry info + p = Extra_SymmPairsAllocate( nSuppSize ); + + // allocate the storage for the temporary map + pMapVars2Nums = ALLOC( int, dd->size ); + memset( pMapVars2Nums, 0, dd->size * sizeof(int) ); + + // assign the variables + p->nVarsMax = dd->size; +// p->nNodes = Cudd_DagSize( zPairs ); + p->nNodes = 0; + for ( i = 0, bTemp = bSupp; bTemp != b1; bTemp = cuddT(bTemp), i++ ) + { + p->pVars[i] = bTemp->index; + pMapVars2Nums[bTemp->index] = i; + } + + // write the symmetry info into the structure + zSet = zPairs; Cudd_Ref( zSet ); + while ( zSet != z0 ) + { + // get the next cube + zCube = Extra_zddSelectOneSubset( dd, zSet ); Cudd_Ref( zCube ); + + // add these two variables to the data structure + assert( cuddT( cuddT(zCube) ) == z1 ); + iVar1 = zCube->index/2; + iVar2 = cuddT(zCube)->index/2; + if ( pMapVars2Nums[iVar1] < pMapVars2Nums[iVar2] ) + p->pSymms[ pMapVars2Nums[iVar1] ][ pMapVars2Nums[iVar2] ] = 1; + else + p->pSymms[ pMapVars2Nums[iVar2] ][ pMapVars2Nums[iVar1] ] = 1; + // count the symmetric pairs + p->nSymms ++; + + // update the cuver and deref the cube + zSet = Cudd_zddDiff( dd, zTemp = zSet, zCube ); Cudd_Ref( zSet ); + Cudd_RecursiveDerefZdd( dd, zTemp ); + Cudd_RecursiveDerefZdd( dd, zCube ); + + } // for each cube + Cudd_RecursiveDerefZdd( dd, zSet ); + + FREE( pMapVars2Nums ); + return p; + +} /* end of Extra_SymmPairsCreateFromZdd */ + + +/**Function******************************************************************** + + Synopsis [Checks the possibility of two variables being symmetric.] + + Description [Returns 0 if vars are not symmetric. Return 1 if vars can be symmetric.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +int Extra_bddCheckVarsSymmetric( + DdManager * dd, /* the DD manager */ + DdNode * bF, + int iVar1, + int iVar2) +{ + DdNode * bVars; + int Res; + +// return 1; + + assert( iVar1 != iVar2 ); + assert( iVar1 < dd->size ); + assert( iVar2 < dd->size ); + + bVars = Cudd_bddAnd( dd, dd->vars[iVar1], dd->vars[iVar2] ); Cudd_Ref( bVars ); + + Res = (int)( extraBddCheckVarsSymmetric( dd, bF, bVars ) == b1 ); + + Cudd_RecursiveDeref( dd, bVars ); + + return Res; +} /* end of Extra_bddCheckVarsSymmetric */ + + +/**Function******************************************************************** + + Synopsis [Computes the classical symmetry information for the function.] + + Description [Uses the naive way of comparing cofactors.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +Extra_SymmInfo_t * Extra_SymmPairsComputeNaive( DdManager * dd, DdNode * bFunc ) +{ + DdNode * bSupp, * bTemp; + int nSuppSize; + Extra_SymmInfo_t * p; + int i, k; + + // compute the support + bSupp = Cudd_Support( dd, bFunc ); Cudd_Ref( bSupp ); + nSuppSize = Extra_bddSuppSize( dd, bSupp ); +//printf( "Support = %d. ", nSuppSize ); +//Extra_bddPrint( dd, bSupp ); +//printf( "%d ", nSuppSize ); + + // allocate the storage for symmetry info + p = Extra_SymmPairsAllocate( nSuppSize ); + + // assign the variables + p->nVarsMax = dd->size; + for ( i = 0, bTemp = bSupp; bTemp != b1; bTemp = cuddT(bTemp), i++ ) + p->pVars[i] = bTemp->index; + + // go through the candidate pairs and check using Idea1 + for ( i = 0; i < nSuppSize; i++ ) + for ( k = i+1; k < nSuppSize; k++ ) + { + p->pSymms[k][i] = p->pSymms[i][k] = Extra_bddCheckVarsSymmetricNaive( dd, bFunc, p->pVars[i], p->pVars[k] ); + if ( p->pSymms[i][k] ) + p->nSymms++; + } + + Cudd_RecursiveDeref( dd, bSupp ); + return p; + +} /* end of Extra_SymmPairsComputeNaive */ + +/**Function******************************************************************** + + Synopsis [Checks if the two variables are symmetric.] + + Description [Returns 0 if vars are not symmetric. Return 1 if vars are symmetric.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +int Extra_bddCheckVarsSymmetricNaive( + DdManager * dd, /* the DD manager */ + DdNode * bF, + int iVar1, + int iVar2) +{ + DdNode * bCube1, * bCube2; + DdNode * bCof01, * bCof10; + int Res; + + assert( iVar1 != iVar2 ); + assert( iVar1 < dd->size ); + assert( iVar2 < dd->size ); + + bCube1 = Cudd_bddAnd( dd, Cudd_Not( dd->vars[iVar1] ), dd->vars[iVar2] ); Cudd_Ref( bCube1 ); + bCube2 = Cudd_bddAnd( dd, Cudd_Not( dd->vars[iVar2] ), dd->vars[iVar1] ); Cudd_Ref( bCube2 ); + + bCof01 = Cudd_Cofactor( dd, bF, bCube1 ); Cudd_Ref( bCof01 ); + bCof10 = Cudd_Cofactor( dd, bF, bCube2 ); Cudd_Ref( bCof10 ); + + Res = (int)( bCof10 == bCof01 ); + + Cudd_RecursiveDeref( dd, bCof01 ); + Cudd_RecursiveDeref( dd, bCof10 ); + Cudd_RecursiveDeref( dd, bCube1 ); + Cudd_RecursiveDeref( dd, bCube2 ); + + return Res; +} /* end of Extra_bddCheckVarsSymmetricNaive */ + + +/**Function******************************************************************** + + Synopsis [Builds ZDD representing the set of fixed-size variable tuples.] + + Description [Creates ZDD of all combinations of variables in Support that + is represented by a BDD.] + + SideEffects [New ZDD variables are created if indices of the variables + present in the combination are larger than the currently + allocated number of ZDD variables.] + + SeeAlso [] + +******************************************************************************/ +DdNode* Extra_zddTuplesFromBdd( + DdManager * dd, /* the DD manager */ + int K, /* the number of variables in tuples */ + DdNode * bVarsN) /* the set of all variables represented as a BDD */ +{ + DdNode *zRes; + int autoDynZ; + + autoDynZ = dd->autoDynZ; + dd->autoDynZ = 0; + + do { + /* transform the numeric arguments (K) into a DdNode* argument; + * this allows us to use the standard internal CUDD cache */ + DdNode *bVarSet = bVarsN, *bVarsK = bVarsN; + int nVars = 0, i; + + /* determine the number of variables in VarSet */ + while ( bVarSet != b1 ) + { + nVars++; + /* make sure that the VarSet is a cube */ + if ( cuddE( bVarSet ) != b0 ) + return NULL; + bVarSet = cuddT( bVarSet ); + } + /* make sure that the number of variables in VarSet is less or equal + that the number of variables that should be present in the tuples + */ + if ( K > nVars ) + return NULL; + + /* the second argument in the recursive call stannds for ; + /* reate the first argument, which stands for + * as when we are talking about the tuple of out of */ + for ( i = 0; i < nVars-K; i++ ) + bVarsK = cuddT( bVarsK ); + + dd->reordered = 0; + zRes = extraZddTuplesFromBdd(dd, bVarsK, bVarsN ); + + } while (dd->reordered == 1); + dd->autoDynZ = autoDynZ; + return zRes; + +} /* end of Extra_zddTuplesFromBdd */ + +/**Function******************************************************************** + + Synopsis [Selects one subset from the set of subsets represented by a ZDD.] + + Description [] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +DdNode* Extra_zddSelectOneSubset( + DdManager * dd, /* the DD manager */ + DdNode * zS) /* the ZDD */ +{ + DdNode *res; + do { + dd->reordered = 0; + res = extraZddSelectOneSubset(dd, zS); + } while (dd->reordered == 1); + return(res); + +} /* end of Extra_zddSelectOneSubset */ + + +/*---------------------------------------------------------------------------*/ +/* Definition of internal functions */ +/*---------------------------------------------------------------------------*/ + +/**Function******************************************************************** + + Synopsis [Performs a recursive step of Extra_SymmPairsCompute.] + + Description [Returns the set of symmetric variable pairs represented as a set + of two-literal ZDD cubes. Both variables always appear in the positive polarity + in the cubes. This function works without building new BDD nodes. Some relatively + small number of ZDD nodes may be built to ensure proper bookkeeping of the + symmetry information.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * +extraZddSymmPairsCompute( + DdManager * dd, /* the manager */ + DdNode * bFunc, /* the function whose symmetries are computed */ + DdNode * bVars ) /* the set of variables on which this function depends */ +{ + DdNode * zRes; + DdNode * bFR = Cudd_Regular(bFunc); + + if ( cuddIsConstant(bFR) ) + { + int nVars, i; + + // determine how many vars are in the bVars + nVars = Extra_bddSuppSize( dd, bVars ); + if ( nVars < 2 ) + return z0; + else + { + DdNode * bVarsK; + + // create the BDD bVarsK corresponding to K = 2; + bVarsK = bVars; + for ( i = 0; i < nVars-2; i++ ) + bVarsK = cuddT( bVarsK ); + return extraZddTuplesFromBdd( dd, bVarsK, bVars ); + } + } + assert( bVars != b1 ); + + if ( zRes = cuddCacheLookup2Zdd(dd, extraZddSymmPairsCompute, bFunc, bVars) ) + return zRes; + else + { + DdNode * zRes0, * zRes1; + DdNode * zTemp, * zPlus, * zSymmVars; + DdNode * bF0, * bF1; + DdNode * bVarsNew; + int nVarsExtra; + int LevelF; + + // every variable in bF should be also in bVars, therefore LevelF cannot be above LevelV + // if LevelF is below LevelV, scroll through the vars in bVars to the same level as F + // count how many extra vars are there in bVars + nVarsExtra = 0; + LevelF = dd->perm[bFR->index]; + for ( bVarsNew = bVars; LevelF > dd->perm[bVarsNew->index]; bVarsNew = cuddT(bVarsNew) ) + nVarsExtra++; + // the indexes (level) of variables should be synchronized now + assert( bFR->index == bVarsNew->index ); + + // cofactor the function + if ( bFR != bFunc ) // bFunc is complemented + { + bF0 = Cudd_Not( cuddE(bFR) ); + bF1 = Cudd_Not( cuddT(bFR) ); + } + else + { + bF0 = cuddE(bFR); + bF1 = cuddT(bFR); + } + + // solve subproblems + zRes0 = extraZddSymmPairsCompute( dd, bF0, cuddT(bVarsNew) ); + if ( zRes0 == NULL ) + return NULL; + cuddRef( zRes0 ); + + // if there is no symmetries in the negative cofactor + // there is no need to test the positive cofactor + if ( zRes0 == z0 ) + zRes = zRes0; // zRes takes reference + else + { + zRes1 = extraZddSymmPairsCompute( dd, bF1, cuddT(bVarsNew) ); + if ( zRes1 == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zRes0 ); + return NULL; + } + cuddRef( zRes1 ); + + // only those variables are pair-wise symmetric + // that are pair-wise symmetric in both cofactors + // therefore, intersect the solutions + zRes = cuddZddIntersect( dd, zRes0, zRes1 ); + if ( zRes == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zRes0 ); + Cudd_RecursiveDerefZdd( dd, zRes1 ); + return NULL; + } + cuddRef( zRes ); + Cudd_RecursiveDerefZdd( dd, zRes0 ); + Cudd_RecursiveDerefZdd( dd, zRes1 ); + } + + // consider the current top-most variable and find all the vars + // that are pairwise symmetric with it + // these variables are returned as a set of ZDD singletons + zSymmVars = extraZddGetSymmetricVars( dd, bF1, bF0, cuddT(bVarsNew) ); + if ( zSymmVars == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zRes ); + return NULL; + } + cuddRef( zSymmVars ); + + // attach the topmost variable to the set, to get the variable pairs + // use the positive polarity ZDD variable for the purpose + + // there is no need to do so, if zSymmVars is empty + if ( zSymmVars == z0 ) + Cudd_RecursiveDerefZdd( dd, zSymmVars ); + else + { + zPlus = cuddZddGetNode( dd, 2*bFR->index, zSymmVars, z0 ); + if ( zPlus == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zRes ); + Cudd_RecursiveDerefZdd( dd, zSymmVars ); + return NULL; + } + cuddRef( zPlus ); + cuddDeref( zSymmVars ); + + // add these variable pairs to the result + zRes = cuddZddUnion( dd, zTemp = zRes, zPlus ); + if ( zRes == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zTemp ); + Cudd_RecursiveDerefZdd( dd, zPlus ); + return NULL; + } + cuddRef( zRes ); + Cudd_RecursiveDerefZdd( dd, zTemp ); + Cudd_RecursiveDerefZdd( dd, zPlus ); + } + + // only zRes is referenced at this point + + // if we skipped some variables, these variables cannot be symmetric with + // any variables that are currently in the support of bF, but they can be + // symmetric with the variables that are in bVars but not in the support of bF + if ( nVarsExtra ) + { + // it is possible to improve this step: + // (1) there is no need to enter here, if nVarsExtra < 2 + + // create the set of topmost nVarsExtra in bVars + DdNode * bVarsExtra; + int nVars; + + // remove from bVars all the variable that are in the support of bFunc + bVarsExtra = extraBddReduceVarSet( dd, bVars, bFunc ); + if ( bVarsExtra == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zRes ); + return NULL; + } + cuddRef( bVarsExtra ); + + // determine how many vars are in the bVarsExtra + nVars = Extra_bddSuppSize( dd, bVarsExtra ); + if ( nVars < 2 ) + { + Cudd_RecursiveDeref( dd, bVarsExtra ); + } + else + { + int i; + DdNode * bVarsK; + + // create the BDD bVarsK corresponding to K = 2; + bVarsK = bVarsExtra; + for ( i = 0; i < nVars-2; i++ ) + bVarsK = cuddT( bVarsK ); + + // create the 2 variable tuples + zPlus = extraZddTuplesFromBdd( dd, bVarsK, bVarsExtra ); + if ( zPlus == NULL ) + { + Cudd_RecursiveDeref( dd, bVarsExtra ); + Cudd_RecursiveDerefZdd( dd, zRes ); + return NULL; + } + cuddRef( zPlus ); + Cudd_RecursiveDeref( dd, bVarsExtra ); + + // add these to the result + zRes = cuddZddUnion( dd, zTemp = zRes, zPlus ); + if ( zRes == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zTemp ); + Cudd_RecursiveDerefZdd( dd, zPlus ); + return NULL; + } + cuddRef( zRes ); + Cudd_RecursiveDerefZdd( dd, zTemp ); + Cudd_RecursiveDerefZdd( dd, zPlus ); + } + } + cuddDeref( zRes ); + + + /* insert the result into cache */ + cuddCacheInsert2(dd, extraZddSymmPairsCompute, bFunc, bVars, zRes); + return zRes; + } +} /* end of extraZddSymmPairsCompute */ + +/**Function******************************************************************** + + Synopsis [Performs a recursive step of Extra_zddGetSymmetricVars.] + + Description [Returns the set of ZDD singletons, containing those positive + ZDD variables that correspond to BDD variables x, for which it is true + that bF(x=0) == bG(x=1).] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * extraZddGetSymmetricVars( + DdManager * dd, /* the DD manager */ + DdNode * bF, /* the first function - originally, the positive cofactor */ + DdNode * bG, /* the second function - originally, the negative cofactor */ + DdNode * bVars) /* the set of variables, on which F and G depend */ +{ + DdNode * zRes; + DdNode * bFR = Cudd_Regular(bF); + DdNode * bGR = Cudd_Regular(bG); + + if ( cuddIsConstant(bFR) && cuddIsConstant(bGR) ) + { + if ( bF == bG ) + return extraZddGetSingletons( dd, bVars ); + else + return z0; + } + assert( bVars != b1 ); + + if ( zRes = cuddCacheLookupZdd(dd, DD_GET_SYMM_VARS_TAG, bF, bG, bVars) ) + return zRes; + else + { + DdNode * zRes0, * zRes1; + DdNode * zPlus, * zTemp; + DdNode * bF0, * bF1; + DdNode * bG0, * bG1; + DdNode * bVarsNew; + + int LevelF = cuddI(dd,bFR->index); + int LevelG = cuddI(dd,bGR->index); + int LevelFG; + + if ( LevelF < LevelG ) + LevelFG = LevelF; + else + LevelFG = LevelG; + + // at least one of the arguments is not a constant + assert( LevelFG < dd->size ); + + // every variable in bF and bG should be also in bVars, therefore LevelFG cannot be above LevelV + // if LevelFG is below LevelV, scroll through the vars in bVars to the same level as LevelFG + for ( bVarsNew = bVars; LevelFG > dd->perm[bVarsNew->index]; bVarsNew = cuddT(bVarsNew) ); + assert( LevelFG == dd->perm[bVarsNew->index] ); + + // cofactor the functions + if ( LevelF == LevelFG ) + { + if ( bFR != bF ) // bF is complemented + { + bF0 = Cudd_Not( cuddE(bFR) ); + bF1 = Cudd_Not( cuddT(bFR) ); + } + else + { + bF0 = cuddE(bFR); + bF1 = cuddT(bFR); + } + } + else + bF0 = bF1 = bF; + + if ( LevelG == LevelFG ) + { + if ( bGR != bG ) // bG is complemented + { + bG0 = Cudd_Not( cuddE(bGR) ); + bG1 = Cudd_Not( cuddT(bGR) ); + } + else + { + bG0 = cuddE(bGR); + bG1 = cuddT(bGR); + } + } + else + bG0 = bG1 = bG; + + // solve subproblems + zRes0 = extraZddGetSymmetricVars( dd, bF0, bG0, cuddT(bVarsNew) ); + if ( zRes0 == NULL ) + return NULL; + cuddRef( zRes0 ); + + // if there is not symmetries in the negative cofactor + // there is no need to test the positive cofactor + if ( zRes0 == z0 ) + zRes = zRes0; // zRes takes reference + else + { + zRes1 = extraZddGetSymmetricVars( dd, bF1, bG1, cuddT(bVarsNew) ); + if ( zRes1 == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zRes0 ); + return NULL; + } + cuddRef( zRes1 ); + + // only those variables should belong to the resulting set + // for which the property is true for both cofactors + zRes = cuddZddIntersect( dd, zRes0, zRes1 ); + if ( zRes == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zRes0 ); + Cudd_RecursiveDerefZdd( dd, zRes1 ); + return NULL; + } + cuddRef( zRes ); + Cudd_RecursiveDerefZdd( dd, zRes0 ); + Cudd_RecursiveDerefZdd( dd, zRes1 ); + } + + // add one more singleton if the property is true for this variable + if ( bF0 == bG1 ) + { + zPlus = cuddZddGetNode( dd, 2*bVarsNew->index, z1, z0 ); + if ( zPlus == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zRes ); + return NULL; + } + cuddRef( zPlus ); + + // add these variable pairs to the result + zRes = cuddZddUnion( dd, zTemp = zRes, zPlus ); + if ( zRes == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zTemp ); + Cudd_RecursiveDerefZdd( dd, zPlus ); + return NULL; + } + cuddRef( zRes ); + Cudd_RecursiveDerefZdd( dd, zTemp ); + Cudd_RecursiveDerefZdd( dd, zPlus ); + } + + if ( bF == bG && bVars != bVarsNew ) + { + // if the functions are equal, so are their cofactors + // add those variables from V that are above F and G + + DdNode * bVarsExtra; + + assert( LevelFG > dd->perm[bVars->index] ); + + // create the BDD of the extra variables + bVarsExtra = cuddBddExistAbstractRecur( dd, bVars, bVarsNew ); + if ( bVarsExtra == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zRes ); + return NULL; + } + cuddRef( bVarsExtra ); + + zPlus = extraZddGetSingletons( dd, bVarsExtra ); + if ( zPlus == NULL ) + { + Cudd_RecursiveDeref( dd, bVarsExtra ); + Cudd_RecursiveDerefZdd( dd, zRes ); + return NULL; + } + cuddRef( zPlus ); + Cudd_RecursiveDeref( dd, bVarsExtra ); + + // add these to the result + zRes = cuddZddUnion( dd, zTemp = zRes, zPlus ); + if ( zRes == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zTemp ); + Cudd_RecursiveDerefZdd( dd, zPlus ); + return NULL; + } + cuddRef( zRes ); + Cudd_RecursiveDerefZdd( dd, zTemp ); + Cudd_RecursiveDerefZdd( dd, zPlus ); + } + cuddDeref( zRes ); + + cuddCacheInsert( dd, DD_GET_SYMM_VARS_TAG, bF, bG, bVars, zRes ); + return zRes; + } +} /* end of extraZddGetSymmetricVars */ + + +/**Function******************************************************************** + + Synopsis [Performs a recursive step of Extra_zddGetSingletons.] + + Description [Returns the set of ZDD singletons, containing those positive + polarity ZDD variables that correspond to the BDD variables in bVars.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * extraZddGetSingletons( + DdManager * dd, /* the DD manager */ + DdNode * bVars) /* the set of variables */ +{ + DdNode * zRes; + + if ( bVars == b1 ) +// if ( bVars == b0 ) // bug fixed by Jin Zhang, Jan 23, 2004 + return z1; + + if ( zRes = cuddCacheLookup1Zdd(dd, extraZddGetSingletons, bVars) ) + return zRes; + else + { + DdNode * zTemp, * zPlus; + + // solve subproblem + zRes = extraZddGetSingletons( dd, cuddT(bVars) ); + if ( zRes == NULL ) + return NULL; + cuddRef( zRes ); + + zPlus = cuddZddGetNode( dd, 2*bVars->index, z1, z0 ); + if ( zPlus == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zRes ); + return NULL; + } + cuddRef( zPlus ); + + // add these to the result + zRes = cuddZddUnion( dd, zTemp = zRes, zPlus ); + if ( zRes == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zTemp ); + Cudd_RecursiveDerefZdd( dd, zPlus ); + return NULL; + } + cuddRef( zRes ); + Cudd_RecursiveDerefZdd( dd, zTemp ); + Cudd_RecursiveDerefZdd( dd, zPlus ); + cuddDeref( zRes ); + + cuddCacheInsert1( dd, extraZddGetSingletons, bVars, zRes ); + return zRes; + } +} /* end of extraZddGetSingletons */ + + +/**Function******************************************************************** + + Synopsis [Performs a recursive step of Extra_bddReduceVarSet.] + + Description [Returns the set of all variables in the given set that are not in the + support of the given function.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * extraBddReduceVarSet( + DdManager * dd, /* the DD manager */ + DdNode * bVars, /* the set of variables to be reduced */ + DdNode * bF) /* the function whose support is used for reduction */ +{ + DdNode * bRes; + DdNode * bFR = Cudd_Regular(bF); + + if ( cuddIsConstant(bFR) || bVars == b1 ) + return bVars; + + if ( bRes = cuddCacheLookup2(dd, extraBddReduceVarSet, bVars, bF) ) + return bRes; + else + { + DdNode * bF0, * bF1; + DdNode * bVarsThis, * bVarsLower, * bTemp; + int LevelF; + + // if LevelF is below LevelV, scroll through the vars in bVars + LevelF = dd->perm[bFR->index]; + for ( bVarsThis = bVars; LevelF > cuddI(dd,bVarsThis->index); bVarsThis = cuddT(bVarsThis) ); + // scroll also through the current var, because it should be not be added + if ( LevelF == cuddI(dd,bVarsThis->index) ) + bVarsLower = cuddT(bVarsThis); + else + bVarsLower = bVarsThis; + + // cofactor the function + if ( bFR != bF ) // bFunc is complemented + { + bF0 = Cudd_Not( cuddE(bFR) ); + bF1 = Cudd_Not( cuddT(bFR) ); + } + else + { + bF0 = cuddE(bFR); + bF1 = cuddT(bFR); + } + + // solve subproblems + bRes = extraBddReduceVarSet( dd, bVarsLower, bF0 ); + if ( bRes == NULL ) + return NULL; + cuddRef( bRes ); + + bRes = extraBddReduceVarSet( dd, bTemp = bRes, bF1 ); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref( dd, bTemp ); + return NULL; + } + cuddRef( bRes ); + Cudd_RecursiveDeref( dd, bTemp ); + + // the current var should not be added + // add the skipped vars + if ( bVarsThis != bVars ) + { + DdNode * bVarsExtra; + + // extract the skipped variables + bVarsExtra = cuddBddExistAbstractRecur( dd, bVars, bVarsThis ); + if ( bVarsExtra == NULL ) + { + Cudd_RecursiveDeref( dd, bRes ); + return NULL; + } + cuddRef( bVarsExtra ); + + // add these variables + bRes = cuddBddAndRecur( dd, bTemp = bRes, bVarsExtra ); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref( dd, bTemp ); + Cudd_RecursiveDeref( dd, bVarsExtra ); + return NULL; + } + cuddRef( bRes ); + Cudd_RecursiveDeref( dd, bTemp ); + Cudd_RecursiveDeref( dd, bVarsExtra ); + } + cuddDeref( bRes ); + + cuddCacheInsert2( dd, extraBddReduceVarSet, bVars, bF, bRes ); + return bRes; + } +} /* end of extraBddReduceVarSet */ + + +/**Function******************************************************************** + + Synopsis [Performs the recursive step of Extra_bddCheckVarsSymmetric().] + + Description [Returns b0 if the variables are not symmetric. Returns b1 if the + variables can be symmetric. The variables are represented in the form of a + two-variable cube. In case the cube contains one variable (below Var1 level), + the cube's pointer is complemented if the variable Var1 occurred on the + current path; otherwise, the cube's pointer is regular. Uses additional + complemented bit (Hash_Not) to mark the result if in the BDD rooted that this + node there is a branch passing though the node labeled with Var2.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * extraBddCheckVarsSymmetric( + DdManager * dd, /* the DD manager */ + DdNode * bF, + DdNode * bVars) +{ + DdNode * bRes; + + if ( bF == b0 ) + return b1; + + assert( bVars != b1 ); + + if ( bRes = cuddCacheLookup2(dd, extraBddCheckVarsSymmetric, bF, bVars) ) + return bRes; + else + { + DdNode * bRes0, * bRes1; + DdNode * bF0, * bF1; + DdNode * bFR = Cudd_Regular(bF); + int LevelF = cuddI(dd,bFR->index); + + DdNode * bVarsR = Cudd_Regular(bVars); + int fVar1Pres; + int iLev1; + int iLev2; + + if ( bVarsR != bVars ) // cube's pointer is complemented + { + assert( cuddT(bVarsR) == b1 ); + fVar1Pres = 1; // the first var is present on the path + iLev1 = -1; // we are already below the first var level + iLev2 = dd->perm[bVarsR->index]; // the level of the second var + } + else // cube's pointer is NOT complemented + { + fVar1Pres = 0; // the first var is absent on the path + if ( cuddT(bVars) == b1 ) + { + iLev1 = -1; // we are already below the first var level + iLev2 = dd->perm[bVars->index]; // the level of the second var + } + else + { + assert( cuddT(cuddT(bVars)) == b1 ); + iLev1 = dd->perm[bVars->index]; // the level of the first var + iLev2 = dd->perm[cuddT(bVars)->index]; // the level of the second var + } + } + + // cofactor the function + // the cofactors are needed only if we are above the second level + if ( LevelF < iLev2 ) + { + if ( bFR != bF ) // bFunc is complemented + { + bF0 = Cudd_Not( cuddE(bFR) ); + bF1 = Cudd_Not( cuddT(bFR) ); + } + else + { + bF0 = cuddE(bFR); + bF1 = cuddT(bFR); + } + } + else + bF0 = bF1 = NULL; + + // consider five cases: + // (1) F is above iLev1 + // (2) F is on the level iLev1 + // (3) F is between iLev1 and iLev2 + // (4) F is on the level iLev2 + // (5) F is below iLev2 + + // (1) F is above iLev1 + if ( LevelF < iLev1 ) + { + // the returned result cannot have the hash attribute + // because we still did not reach the level of Var1; + // the attribute never travels above the level of Var1 + bRes0 = extraBddCheckVarsSymmetric( dd, bF0, bVars ); +// assert( !Hash_IsComplement( bRes0 ) ); + assert( bRes0 != z0 ); + if ( bRes0 == b0 ) + bRes = b0; + else + bRes = extraBddCheckVarsSymmetric( dd, bF1, bVars ); +// assert( !Hash_IsComplement( bRes ) ); + assert( bRes != z0 ); + } + // (2) F is on the level iLev1 + else if ( LevelF == iLev1 ) + { + bRes0 = extraBddCheckVarsSymmetric( dd, bF0, Cudd_Not( cuddT(bVars) ) ); + if ( bRes0 == b0 ) + bRes = b0; + else + { + bRes1 = extraBddCheckVarsSymmetric( dd, bF1, Cudd_Not( cuddT(bVars) ) ); + if ( bRes1 == b0 ) + bRes = b0; + else + { +// if ( Hash_IsComplement( bRes0 ) || Hash_IsComplement( bRes1 ) ) + if ( bRes0 == z0 || bRes1 == z0 ) + bRes = b1; + else + bRes = b0; + } + } + } + // (3) F is between iLev1 and iLev2 + else if ( LevelF < iLev2 ) + { + bRes0 = extraBddCheckVarsSymmetric( dd, bF0, bVars ); + if ( bRes0 == b0 ) + bRes = b0; + else + { + bRes1 = extraBddCheckVarsSymmetric( dd, bF1, bVars ); + if ( bRes1 == b0 ) + bRes = b0; + else + { +// if ( Hash_IsComplement( bRes0 ) || Hash_IsComplement( bRes1 ) ) +// bRes = Hash_Not( b1 ); + if ( bRes0 == z0 || bRes1 == z0 ) + bRes = z0; + else + bRes = b1; + } + } + } + // (4) F is on the level iLev2 + else if ( LevelF == iLev2 ) + { + // this is the only place where the hash attribute (Hash_Not) can be added + // to the result; it can be added only if the path came through the node + // lebeled with Var1; therefore, the hash attribute cannot be returned + // to the caller function + if ( fVar1Pres ) +// bRes = Hash_Not( b1 ); + bRes = z0; + else + bRes = b0; + } + // (5) F is below iLev2 + else // if ( LevelF > iLev2 ) + { + // it is possible that the path goes through the node labeled by Var1 + // and still everything is okay; we do not label with Hash_Not here + // because the path does not go through node labeled by Var2 + bRes = b1; + } + + cuddCacheInsert2(dd, extraBddCheckVarsSymmetric, bF, bVars, bRes); + return bRes; + } +} /* end of extraBddCheckVarsSymmetric */ + +/**Function******************************************************************** + + Synopsis [Performs the reordering-sensitive step of Extra_zddTupleFromBdd().] + + Description [Generates in a bottom-up fashion ZDD for all combinations + composed of k variables out of variables belonging to Support.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode* extraZddTuplesFromBdd( + DdManager * dd, /* the DD manager */ + DdNode * bVarsK, /* the number of variables in tuples */ + DdNode * bVarsN) /* the set of all variables */ +{ + DdNode *zRes, *zRes0, *zRes1; + statLine(dd); + + /* terminal cases */ +/* if ( k < 0 || k > n ) + * return dd->zero; + * if ( n == 0 ) + * return dd->one; + */ + if ( cuddI( dd, bVarsK->index ) < cuddI( dd, bVarsN->index ) ) + return z0; + if ( bVarsN == b1 ) + return z1; + + /* check cache */ + zRes = cuddCacheLookup2Zdd(dd, extraZddTuplesFromBdd, bVarsK, bVarsN); + if (zRes) + return(zRes); + + /* ZDD in which this variable is 0 */ +/* zRes0 = extraZddTuplesFromBdd( dd, k, n-1 ); */ + zRes0 = extraZddTuplesFromBdd( dd, bVarsK, cuddT(bVarsN) ); + if ( zRes0 == NULL ) + return NULL; + cuddRef( zRes0 ); + + /* ZDD in which this variable is 1 */ +/* zRes1 = extraZddTuplesFromBdd( dd, k-1, n-1 ); */ + if ( bVarsK == b1 ) + { + zRes1 = z0; + cuddRef( zRes1 ); + } + else + { + zRes1 = extraZddTuplesFromBdd( dd, cuddT(bVarsK), cuddT(bVarsN) ); + if ( zRes1 == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zRes0 ); + return NULL; + } + cuddRef( zRes1 ); + } + + /* compose Res0 and Res1 with the given ZDD variable */ + zRes = cuddZddGetNode( dd, 2*bVarsN->index, zRes1, zRes0 ); + if ( zRes == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zRes0 ); + Cudd_RecursiveDerefZdd( dd, zRes1 ); + return NULL; + } + cuddDeref( zRes0 ); + cuddDeref( zRes1 ); + + /* insert the result into cache */ + cuddCacheInsert2(dd, extraZddTuplesFromBdd, bVarsK, bVarsN, zRes); + return zRes; + +} /* end of extraZddTuplesFromBdd */ + + +/**Function******************************************************************** + + Synopsis [Performs the recursive step of Extra_zddSelectOneSubset.] + + Description [] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +DdNode * extraZddSelectOneSubset( + DdManager * dd, + DdNode * zS ) +// selects one subset from the ZDD zS +// returns z0 if and only if zS is an empty set of cubes +{ + DdNode * zRes; + + if ( zS == z0 ) return z0; + if ( zS == z1 ) return z1; + + // check cache + if ( zRes = cuddCacheLookup1Zdd( dd, extraZddSelectOneSubset, zS ) ) + return zRes; + else + { + DdNode * zS0, * zS1, * zTemp; + + zS0 = cuddE(zS); + zS1 = cuddT(zS); + + if ( zS0 != z0 ) + { + zRes = extraZddSelectOneSubset( dd, zS0 ); + if ( zRes == NULL ) + return NULL; + } + else // if ( zS0 == z0 ) + { + assert( zS1 != z0 ); + zRes = extraZddSelectOneSubset( dd, zS1 ); + if ( zRes == NULL ) + return NULL; + cuddRef( zRes ); + + zRes = cuddZddGetNode( dd, zS->index, zTemp = zRes, z0 ); + if ( zRes == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zTemp ); + return NULL; + } + cuddDeref( zTemp ); + } + + // insert the result into cache + cuddCacheInsert1( dd, extraZddSelectOneSubset, zS, zRes ); + return zRes; + } +} /* end of extraZddSelectOneSubset */ + + +/*---------------------------------------------------------------------------*/ +/* Definition of static Functions */ +/*---------------------------------------------------------------------------*/ diff --git a/src/misc/extra/extraBddUnate.c b/src/misc/extra/extraBddUnate.c new file mode 100644 index 00000000..b0297c77 --- /dev/null +++ b/src/misc/extra/extraBddUnate.c @@ -0,0 +1,641 @@ +/**CFile**************************************************************** + + FileName [extraBddUnate.c] + + PackageName [extra] + + Synopsis [Efficient methods to compute the information about + unate variables using an algorithm that is conceptually similar to + the algorithm for two-variable symmetry computation presented in: + A. Mishchenko. Fast Computation of Symmetries in Boolean Functions. + Transactions on CAD, Nov. 2003.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 2.0. Started - September 1, 2003.] + + Revision [$Id: extraBddUnate.c,v 1.0 2003/09/01 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "extra.h" + +/*---------------------------------------------------------------------------*/ +/* Constant declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Stucture declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Type declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Variable declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Macro declarations */ +/*---------------------------------------------------------------------------*/ + +/**AutomaticStart*************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Static function prototypes */ +/*---------------------------------------------------------------------------*/ + +/**AutomaticEnd***************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Definition of exported functions */ +/*---------------------------------------------------------------------------*/ + + +/**Function******************************************************************** + + Synopsis [Computes the classical symmetry information for the function.] + + Description [Returns the symmetry information in the form of Extra_UnateInfo_t structure.] + + SideEffects [If the ZDD variables are not derived from BDD variables with + multiplicity 2, this function may derive them in a wrong way.] + + SeeAlso [] + +******************************************************************************/ +Extra_UnateInfo_t * Extra_UnateComputeFast( + DdManager * dd, /* the manager */ + DdNode * bFunc) /* the function whose symmetries are computed */ +{ + DdNode * bSupp; + DdNode * zRes; + Extra_UnateInfo_t * p; + + bSupp = Cudd_Support( dd, bFunc ); Cudd_Ref( bSupp ); + zRes = Extra_zddUnateInfoCompute( dd, bFunc, bSupp ); Cudd_Ref( zRes ); + + p = Extra_UnateInfoCreateFromZdd( dd, zRes, bSupp ); + + Cudd_RecursiveDeref( dd, bSupp ); + Cudd_RecursiveDerefZdd( dd, zRes ); + + return p; + +} /* end of Extra_UnateInfoCompute */ + + +/**Function******************************************************************** + + Synopsis [Computes the classical symmetry information as a ZDD.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_zddUnateInfoCompute( + DdManager * dd, /* the DD manager */ + DdNode * bF, + DdNode * bVars) +{ + DdNode * res; + do { + dd->reordered = 0; + res = extraZddUnateInfoCompute( dd, bF, bVars ); + } while (dd->reordered == 1); + return(res); + +} /* end of Extra_zddUnateInfoCompute */ + + +/**Function******************************************************************** + + Synopsis [Converts a set of variables into a set of singleton subsets.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_zddGetSingletonsBoth( + DdManager * dd, /* the DD manager */ + DdNode * bVars) /* the set of variables */ +{ + DdNode * res; + do { + dd->reordered = 0; + res = extraZddGetSingletonsBoth( dd, bVars ); + } while (dd->reordered == 1); + return(res); + +} /* end of Extra_zddGetSingletonsBoth */ + +/**Function******************************************************************** + + Synopsis [Allocates unateness information structure.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +Extra_UnateInfo_t * Extra_UnateInfoAllocate( int nVars ) +{ + Extra_UnateInfo_t * p; + // allocate and clean the storage for unateness info + p = ALLOC( Extra_UnateInfo_t, 1 ); + memset( p, 0, sizeof(Extra_UnateInfo_t) ); + p->nVars = nVars; + p->pVars = ALLOC( Extra_UnateVar_t, nVars ); + memset( p->pVars, 0, nVars * sizeof(Extra_UnateVar_t) ); + return p; +} /* end of Extra_UnateInfoAllocate */ + +/**Function******************************************************************** + + Synopsis [Deallocates symmetry information structure.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +void Extra_UnateInfoDissolve( Extra_UnateInfo_t * p ) +{ + free( p->pVars ); + free( p ); +} /* end of Extra_UnateInfoDissolve */ + +/**Function******************************************************************** + + Synopsis [Allocates symmetry information structure.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +void Extra_UnateInfoPrint( Extra_UnateInfo_t * p ) +{ + char * pBuffer; + int i; + pBuffer = ALLOC( char, p->nVarsMax+1 ); + memset( pBuffer, ' ', p->nVarsMax ); + pBuffer[p->nVarsMax] = 0; + for ( i = 0; i < p->nVars; i++ ) + if ( p->pVars[i].Neg ) + pBuffer[ p->pVars[i].iVar ] = 'n'; + else if ( p->pVars[i].Pos ) + pBuffer[ p->pVars[i].iVar ] = 'p'; + else + pBuffer[ p->pVars[i].iVar ] = '.'; + printf( "%s\n", pBuffer ); + free( pBuffer ); +} /* end of Extra_UnateInfoPrint */ + + +/**Function******************************************************************** + + Synopsis [Creates the symmetry information structure from ZDD.] + + Description [ZDD representation of symmetries is the set of cubes, each + of which has two variables in the positive polarity. These variables correspond + to the symmetric variable pair.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +Extra_UnateInfo_t * Extra_UnateInfoCreateFromZdd( DdManager * dd, DdNode * zPairs, DdNode * bSupp ) +{ + Extra_UnateInfo_t * p; + DdNode * bTemp, * zSet, * zCube, * zTemp; + int * pMapVars2Nums; + int i, nSuppSize; + + nSuppSize = Extra_bddSuppSize( dd, bSupp ); + + // allocate and clean the storage for symmetry info + p = Extra_UnateInfoAllocate( nSuppSize ); + + // allocate the storage for the temporary map + pMapVars2Nums = ALLOC( int, dd->size ); + memset( pMapVars2Nums, 0, dd->size * sizeof(int) ); + + // assign the variables + p->nVarsMax = dd->size; + for ( i = 0, bTemp = bSupp; bTemp != b1; bTemp = cuddT(bTemp), i++ ) + { + p->pVars[i].iVar = bTemp->index; + pMapVars2Nums[bTemp->index] = i; + } + + // write the symmetry info into the structure + zSet = zPairs; Cudd_Ref( zSet ); +// Cudd_zddPrintCover( dd, zPairs ); printf( "\n" ); + while ( zSet != z0 ) + { + // get the next cube + zCube = Extra_zddSelectOneSubset( dd, zSet ); Cudd_Ref( zCube ); + + // add this var to the data structure + assert( cuddT(zCube) == z1 && cuddE(zCube) == z0 ); + if ( zCube->index & 1 ) // neg + p->pVars[ pMapVars2Nums[zCube->index/2] ].Neg = 1; + else + p->pVars[ pMapVars2Nums[zCube->index/2] ].Pos = 1; + // count the unate vars + p->nUnate++; + + // update the cuver and deref the cube + zSet = Cudd_zddDiff( dd, zTemp = zSet, zCube ); Cudd_Ref( zSet ); + Cudd_RecursiveDerefZdd( dd, zTemp ); + Cudd_RecursiveDerefZdd( dd, zCube ); + + } // for each cube + Cudd_RecursiveDerefZdd( dd, zSet ); + FREE( pMapVars2Nums ); + return p; + +} /* end of Extra_UnateInfoCreateFromZdd */ + + + +/**Function******************************************************************** + + Synopsis [Computes the classical unateness information for the function.] + + Description [Uses the naive way of comparing cofactors.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +Extra_UnateInfo_t * Extra_UnateComputeSlow( DdManager * dd, DdNode * bFunc ) +{ + int nSuppSize; + DdNode * bSupp, * bTemp; + Extra_UnateInfo_t * p; + int i, Res; + + // compute the support + bSupp = Cudd_Support( dd, bFunc ); Cudd_Ref( bSupp ); + nSuppSize = Extra_bddSuppSize( dd, bSupp ); +//printf( "Support = %d. ", nSuppSize ); +//Extra_bddPrint( dd, bSupp ); +//printf( "%d ", nSuppSize ); + + // allocate the storage for symmetry info + p = Extra_UnateInfoAllocate( nSuppSize ); + + // assign the variables + p->nVarsMax = dd->size; + for ( i = 0, bTemp = bSupp; bTemp != b1; bTemp = cuddT(bTemp), i++ ) + { + Res = Extra_bddCheckUnateNaive( dd, bFunc, bTemp->index ); + p->pVars[i].iVar = bTemp->index; + if ( Res == -1 ) + p->pVars[i].Neg = 1; + else if ( Res == 1 ) + p->pVars[i].Pos = 1; + p->nUnate += (Res != 0); + } + Cudd_RecursiveDeref( dd, bSupp ); + return p; + +} /* end of Extra_UnateComputeSlow */ + +/**Function******************************************************************** + + Synopsis [Checks if the two variables are symmetric.] + + Description [Returns 0 if vars are not unate. Return -1/+1 if the var is neg/pos unate.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +int Extra_bddCheckUnateNaive( + DdManager * dd, /* the DD manager */ + DdNode * bF, + int iVar) +{ + DdNode * bCof0, * bCof1; + int Res; + + assert( iVar < dd->size ); + + bCof0 = Cudd_Cofactor( dd, bF, Cudd_Not(Cudd_bddIthVar(dd,iVar)) ); Cudd_Ref( bCof0 ); + bCof1 = Cudd_Cofactor( dd, bF, Cudd_bddIthVar(dd,iVar) ); Cudd_Ref( bCof1 ); + + if ( Cudd_bddLeq( dd, bCof0, bCof1 ) ) + Res = 1; + else if ( Cudd_bddLeq( dd, bCof1, bCof0 ) ) + Res =-1; + else + Res = 0; + + Cudd_RecursiveDeref( dd, bCof0 ); + Cudd_RecursiveDeref( dd, bCof1 ); + return Res; +} /* end of Extra_bddCheckUnateNaive */ + + + +/*---------------------------------------------------------------------------*/ +/* Definition of internal functions */ +/*---------------------------------------------------------------------------*/ + +/**Function******************************************************************** + + Synopsis [Performs a recursive step of Extra_UnateInfoCompute.] + + Description [Returns the set of symmetric variable pairs represented as a set + of two-literal ZDD cubes. Both variables always appear in the positive polarity + in the cubes. This function works without building new BDD nodes. Some relatively + small number of ZDD nodes may be built to ensure proper bookkeeping of the + symmetry information.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * +extraZddUnateInfoCompute( + DdManager * dd, /* the manager */ + DdNode * bFunc, /* the function whose symmetries are computed */ + DdNode * bVars ) /* the set of variables on which this function depends */ +{ + DdNode * zRes; + DdNode * bFR = Cudd_Regular(bFunc); + + if ( cuddIsConstant(bFR) ) + { + if ( cuddIsConstant(bVars) ) + return z0; + return extraZddGetSingletonsBoth( dd, bVars ); + } + assert( bVars != b1 ); + + if ( zRes = cuddCacheLookup2Zdd(dd, extraZddUnateInfoCompute, bFunc, bVars) ) + return zRes; + else + { + DdNode * zRes0, * zRes1; + DdNode * zTemp, * zPlus; + DdNode * bF0, * bF1; + DdNode * bVarsNew; + int nVarsExtra; + int LevelF; + int AddVar; + + // every variable in bF should be also in bVars, therefore LevelF cannot be above LevelV + // if LevelF is below LevelV, scroll through the vars in bVars to the same level as F + // count how many extra vars are there in bVars + nVarsExtra = 0; + LevelF = dd->perm[bFR->index]; + for ( bVarsNew = bVars; LevelF > dd->perm[bVarsNew->index]; bVarsNew = cuddT(bVarsNew) ) + nVarsExtra++; + // the indexes (level) of variables should be synchronized now + assert( bFR->index == bVarsNew->index ); + + // cofactor the function + if ( bFR != bFunc ) // bFunc is complemented + { + bF0 = Cudd_Not( cuddE(bFR) ); + bF1 = Cudd_Not( cuddT(bFR) ); + } + else + { + bF0 = cuddE(bFR); + bF1 = cuddT(bFR); + } + + // solve subproblems + zRes0 = extraZddUnateInfoCompute( dd, bF0, cuddT(bVarsNew) ); + if ( zRes0 == NULL ) + return NULL; + cuddRef( zRes0 ); + + // if there is no symmetries in the negative cofactor + // there is no need to test the positive cofactor + if ( zRes0 == z0 ) + zRes = zRes0; // zRes takes reference + else + { + zRes1 = extraZddUnateInfoCompute( dd, bF1, cuddT(bVarsNew) ); + if ( zRes1 == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zRes0 ); + return NULL; + } + cuddRef( zRes1 ); + + // only those variables are pair-wise symmetric + // that are pair-wise symmetric in both cofactors + // therefore, intersect the solutions + zRes = cuddZddIntersect( dd, zRes0, zRes1 ); + if ( zRes == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zRes0 ); + Cudd_RecursiveDerefZdd( dd, zRes1 ); + return NULL; + } + cuddRef( zRes ); + Cudd_RecursiveDerefZdd( dd, zRes0 ); + Cudd_RecursiveDerefZdd( dd, zRes1 ); + } + + // consider the current top-most variable + AddVar = -1; + if ( Cudd_bddLeq( dd, bF0, bF1 ) ) // pos + AddVar = 0; + else if ( Cudd_bddLeq( dd, bF1, bF0 ) ) // neg + AddVar = 1; + if ( AddVar >= 0 ) + { + // create the singleton + zPlus = cuddZddGetNode( dd, 2*bFR->index + AddVar, z1, z0 ); + if ( zPlus == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zRes ); + return NULL; + } + cuddRef( zPlus ); + + // add these to the result + zRes = cuddZddUnion( dd, zTemp = zRes, zPlus ); + if ( zRes == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zTemp ); + Cudd_RecursiveDerefZdd( dd, zPlus ); + return NULL; + } + cuddRef( zRes ); + Cudd_RecursiveDerefZdd( dd, zTemp ); + Cudd_RecursiveDerefZdd( dd, zPlus ); + } + // only zRes is referenced at this point + + // if we skipped some variables, these variables cannot be symmetric with + // any variables that are currently in the support of bF, but they can be + // symmetric with the variables that are in bVars but not in the support of bF + for ( bVarsNew = bVars; LevelF > dd->perm[bVarsNew->index]; bVarsNew = cuddT(bVarsNew) ) + { + // create the negative singleton + zPlus = cuddZddGetNode( dd, 2*bVarsNew->index+1, z1, z0 ); + if ( zPlus == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zRes ); + return NULL; + } + cuddRef( zPlus ); + + // add these to the result + zRes = cuddZddUnion( dd, zTemp = zRes, zPlus ); + if ( zRes == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zTemp ); + Cudd_RecursiveDerefZdd( dd, zPlus ); + return NULL; + } + cuddRef( zRes ); + Cudd_RecursiveDerefZdd( dd, zTemp ); + Cudd_RecursiveDerefZdd( dd, zPlus ); + + + // create the positive singleton + zPlus = cuddZddGetNode( dd, 2*bVarsNew->index, z1, z0 ); + if ( zPlus == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zRes ); + return NULL; + } + cuddRef( zPlus ); + + // add these to the result + zRes = cuddZddUnion( dd, zTemp = zRes, zPlus ); + if ( zRes == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zTemp ); + Cudd_RecursiveDerefZdd( dd, zPlus ); + return NULL; + } + cuddRef( zRes ); + Cudd_RecursiveDerefZdd( dd, zTemp ); + Cudd_RecursiveDerefZdd( dd, zPlus ); + } + cuddDeref( zRes ); + + /* insert the result into cache */ + cuddCacheInsert2(dd, extraZddUnateInfoCompute, bFunc, bVars, zRes); + return zRes; + } +} /* end of extraZddUnateInfoCompute */ + + +/**Function******************************************************************** + + Synopsis [Performs a recursive step of Extra_zddGetSingletons.] + + Description [Returns the set of ZDD singletons, containing those pos/neg + polarity ZDD variables that correspond to the BDD variables in bVars.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * extraZddGetSingletonsBoth( + DdManager * dd, /* the DD manager */ + DdNode * bVars) /* the set of variables */ +{ + DdNode * zRes; + + if ( bVars == b1 ) + return z1; + + if ( zRes = cuddCacheLookup1Zdd(dd, extraZddGetSingletonsBoth, bVars) ) + return zRes; + else + { + DdNode * zTemp, * zPlus; + + // solve subproblem + zRes = extraZddGetSingletonsBoth( dd, cuddT(bVars) ); + if ( zRes == NULL ) + return NULL; + cuddRef( zRes ); + + + // create the negative singleton + zPlus = cuddZddGetNode( dd, 2*bVars->index+1, z1, z0 ); + if ( zPlus == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zRes ); + return NULL; + } + cuddRef( zPlus ); + + // add these to the result + zRes = cuddZddUnion( dd, zTemp = zRes, zPlus ); + if ( zRes == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zTemp ); + Cudd_RecursiveDerefZdd( dd, zPlus ); + return NULL; + } + cuddRef( zRes ); + Cudd_RecursiveDerefZdd( dd, zTemp ); + Cudd_RecursiveDerefZdd( dd, zPlus ); + + + // create the positive singleton + zPlus = cuddZddGetNode( dd, 2*bVars->index, z1, z0 ); + if ( zPlus == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zRes ); + return NULL; + } + cuddRef( zPlus ); + + // add these to the result + zRes = cuddZddUnion( dd, zTemp = zRes, zPlus ); + if ( zRes == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zTemp ); + Cudd_RecursiveDerefZdd( dd, zPlus ); + return NULL; + } + cuddRef( zRes ); + Cudd_RecursiveDerefZdd( dd, zTemp ); + Cudd_RecursiveDerefZdd( dd, zPlus ); + + cuddDeref( zRes ); + cuddCacheInsert1( dd, extraZddGetSingletonsBoth, bVars, zRes ); + return zRes; + } +} /* end of extraZddGetSingletonsBoth */ + + +/*---------------------------------------------------------------------------*/ +/* Definition of static Functions */ +/*---------------------------------------------------------------------------*/ diff --git a/src/misc/extra/extraUtilBitMatrix.c b/src/misc/extra/extraUtilBitMatrix.c new file mode 100644 index 00000000..b860a538 --- /dev/null +++ b/src/misc/extra/extraUtilBitMatrix.c @@ -0,0 +1,415 @@ +/**CFile**************************************************************** + + FileName [extraUtilBitMatrix.c] + + PackageName [extra] + + Synopsis [Various reusable software utilities.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - September 1, 2003.] + + Revision [$Id: extraUtilBitMatrix.c,v 1.0 2003/09/01 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "extra.h" + +/*---------------------------------------------------------------------------*/ +/* Constant declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Stucture declarations */ +/*---------------------------------------------------------------------------*/ + +struct Extra_BitMat_t_ +{ + unsigned ** ppData; // bit data + int nSize; // the number of bits in one dimension + int nWords; // the number of words in one dimension + int nBitShift; // the number of bits to shift to get words + unsigned uMask; // the mask to get the number of bits in the word + int nLookups; // the number of lookups + int nInserts; // the number of inserts + int nDeletes; // the number of deletions +}; + +/*---------------------------------------------------------------------------*/ +/* Type declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Variable declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Macro declarations */ +/*---------------------------------------------------------------------------*/ + + +/**AutomaticStart*************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Static function prototypes */ +/*---------------------------------------------------------------------------*/ + +/**AutomaticEnd***************************************************************/ + + +/*---------------------------------------------------------------------------*/ +/* Definition of exported functions */ +/*---------------------------------------------------------------------------*/ + +/**Function************************************************************* + + Synopsis [Starts the bit matrix.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Extra_BitMat_t * Extra_BitMatrixStart( int nSize ) +{ + Extra_BitMat_t * p; + int i; + p = ALLOC( Extra_BitMat_t, 1 ); + memset( p, 0, sizeof(Extra_BitMat_t) ); + p->nSize = nSize; + p->nBitShift = (sizeof(unsigned) == 4) ? 5: 6; + p->uMask = (sizeof(unsigned) == 4) ? 31: 63; + p->nWords = nSize / (8 * sizeof(unsigned)) + ((nSize % (8 * sizeof(unsigned))) > 0); + p->ppData = ALLOC( unsigned *, nSize ); + p->ppData[0] = ALLOC( unsigned, nSize * p->nWords ); + memset( p->ppData[0], 0, sizeof(unsigned) * nSize * p->nWords ); + for ( i = 1; i < nSize; i++ ) + p->ppData[i] = p->ppData[i-1] + p->nWords; + return p; +} + +/**Function************************************************************* + + Synopsis [Stops the bit matrix.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_BitMatrixClean( Extra_BitMat_t * p ) +{ + memset( p->ppData[0], 0, sizeof(unsigned) * p->nSize * p->nWords ); +} + +/**Function************************************************************* + + Synopsis [Stops the bit matrix.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_BitMatrixStop( Extra_BitMat_t * p ) +{ + FREE( p->ppData[0] ); + FREE( p->ppData ); + FREE( p ); +} + +/**Function************************************************************* + + Synopsis [Prints the bit-matrix.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_BitMatrixPrint( Extra_BitMat_t * pMat ) +{ + int i, k, nVars; + printf( "\n" ); + nVars = Extra_BitMatrixReadSize( pMat ); + for ( i = 0; i < nVars; i++ ) + { + for ( k = 0; k <= i; k++ ) + printf( " " ); + for ( k = i+1; k < nVars; k++ ) + if ( Extra_BitMatrixLookup1( pMat, i, k ) ) + printf( "1" ); + else + printf( "." ); + printf( "\n" ); + } +} + + +/**Function************************************************************* + + Synopsis [Reads the matrix size.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Extra_BitMatrixReadSize( Extra_BitMat_t * p ) +{ + return p->nSize; +} + +/**Function************************************************************* + + Synopsis [Inserts the element into the upper part.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_BitMatrixInsert1( Extra_BitMat_t * p, int i, int k ) +{ + p->nInserts++; + if ( i < k ) + p->ppData[i][k>>p->nBitShift] |= (1<<(k & p->uMask)); + else + p->ppData[k][i>>p->nBitShift] |= (1<<(i & p->uMask)); +} + +/**Function************************************************************* + + Synopsis [Inserts the element into the upper part.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Extra_BitMatrixLookup1( Extra_BitMat_t * p, int i, int k ) +{ + p->nLookups++; + if ( i < k ) + return ((p->ppData[i][k>>p->nBitShift] & (1<<(k & p->uMask))) > 0); + else + return ((p->ppData[k][i>>p->nBitShift] & (1<<(i & p->uMask))) > 0); +} + +/**Function************************************************************* + + Synopsis [Inserts the element into the upper part.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_BitMatrixDelete1( Extra_BitMat_t * p, int i, int k ) +{ + p->nDeletes++; + if ( i < k ) + p->ppData[i][k>>p->nBitShift] &= ~(1<<(k & p->uMask)); + else + p->ppData[k][i>>p->nBitShift] &= ~(1<<(i & p->uMask)); +} + + + +/**Function************************************************************* + + Synopsis [Inserts the element into the upper part.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_BitMatrixInsert2( Extra_BitMat_t * p, int i, int k ) +{ + p->nInserts++; + if ( i > k ) + p->ppData[i][k>>p->nBitShift] |= (1<<(k & p->uMask)); + else + p->ppData[k][i>>p->nBitShift] |= (1<<(i & p->uMask)); +} + +/**Function************************************************************* + + Synopsis [Inserts the element into the upper part.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Extra_BitMatrixLookup2( Extra_BitMat_t * p, int i, int k ) +{ + p->nLookups++; + if ( i > k ) + return ((p->ppData[i][k>>p->nBitShift] & (1<<(k & p->uMask))) > 0); + else + return ((p->ppData[k][i>>p->nBitShift] & (1<<(i & p->uMask))) > 0); +} + +/**Function************************************************************* + + Synopsis [Inserts the element into the upper part.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_BitMatrixDelete2( Extra_BitMat_t * p, int i, int k ) +{ + p->nDeletes++; + if ( i > k ) + p->ppData[i][k>>p->nBitShift] &= ~(1<<(k & p->uMask)); + else + p->ppData[k][i>>p->nBitShift] &= ~(1<<(i & p->uMask)); +} + + +/**Function************************************************************* + + Synopsis [Inserts the element into the upper part.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_BitMatrixOr( Extra_BitMat_t * p, int i, unsigned * pInfo ) +{ + int w; + for ( w = 0; w < p->nWords; w++ ) + p->ppData[i][w] |= pInfo[w]; +} + +/**Function************************************************************* + + Synopsis [Inserts the element into the upper part.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_BitMatrixOrTwo( Extra_BitMat_t * p, int i, int j ) +{ + int w; + for ( w = 0; w < p->nWords; w++ ) + p->ppData[i][w] = p->ppData[j][w] = (p->ppData[i][w] | p->ppData[j][w]); +} + +/**Function************************************************************* + + Synopsis [Counts the number of 1's in the upper rectangle.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Extra_BitMatrixCountOnesUpper( Extra_BitMat_t * p ) +{ + int i, k, nTotal = 0; + for ( i = 0; i < p->nSize; i++ ) + for ( k = i + 1; k < p->nSize; k++ ) + nTotal += ( (p->ppData[i][k>>5] & (1 << (k&31))) > 0 ); + return nTotal; +} + +/**Function************************************************************* + + Synopsis [Returns 1 if the matrices have no entries in common.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Extra_BitMatrixIsDisjoint( Extra_BitMat_t * p1, Extra_BitMat_t * p2 ) +{ + int i, w; + assert( p1->nSize == p2->nSize ); + for ( i = 0; i < p1->nSize; i++ ) + for ( w = 0; w < p1->nWords; w++ ) + if ( p1->ppData[i][w] & p2->ppData[i][w] ) + return 0; + return 1; +} + +/**Function************************************************************* + + Synopsis [Returns 1 if the matrix is a set of cliques.] + + Description [For example pairwise symmetry info should satisfy this property.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Extra_BitMatrixIsClique( Extra_BitMat_t * pMat ) +{ + int v, u, i; + for ( v = 0; v < pMat->nSize; v++ ) + for ( u = v+1; u < pMat->nSize; u++ ) + { + if ( !Extra_BitMatrixLookup1( pMat, v, u ) ) + continue; + // v and u are symmetric + for ( i = 0; i < pMat->nSize; i++ ) + { + if ( i == v || i == u ) + continue; + // i is neither v nor u + // the symmetry status of i is the same w.r.t. to v and u + if ( Extra_BitMatrixLookup1( pMat, i, v ) != Extra_BitMatrixLookup1( pMat, i, u ) ) + return 0; + } + } + return 1; +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/misc/extra/extraUtilCanon.c b/src/misc/extra/extraUtilCanon.c new file mode 100644 index 00000000..fcc7d84d --- /dev/null +++ b/src/misc/extra/extraUtilCanon.c @@ -0,0 +1,701 @@ +/**CFile**************************************************************** + + FileName [extraUtilMisc.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [extra] + + Synopsis [Computing canonical forms of Boolean functions using truth tables.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: extraUtilMisc.c,v 1.0 2003/09/01 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "extra.h" + +/*---------------------------------------------------------------------------*/ +/* Constant declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Stucture declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Type declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Variable declarations */ +/*---------------------------------------------------------------------------*/ + +static unsigned s_Truths3[256]; +static char s_Phases3[256][9]; + +/*---------------------------------------------------------------------------*/ +/* Macro declarations */ +/*---------------------------------------------------------------------------*/ + + +/**AutomaticStart*************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Static function prototypes */ +/*---------------------------------------------------------------------------*/ + +static int Extra_TruthCanonN_rec( int nVars, unsigned char * pt, unsigned ** pptRes, char ** ppfRes, int Flag ); + +/**AutomaticEnd***************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Definition of exported functions */ +/*---------------------------------------------------------------------------*/ + +/**Function******************************************************************** + + Synopsis [Computes the N-canonical form of the Boolean function up to 6 inputs.] + + Description [The N-canonical form is defined as the truth table with + the minimum integer value. This function exhaustively enumerates + through the complete set of 2^N phase assignments. + Returns pointers to the static storage to the truth table and phases. + This data should be used before the function is called again.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +int Extra_TruthCanonFastN( int nVarsMax, int nVarsReal, unsigned * pt, unsigned ** pptRes, char ** ppfRes ) +{ + static unsigned uTruthStore6[2]; + int RetValue; + assert( nVarsMax <= 6 ); + assert( nVarsReal <= nVarsMax ); + RetValue = Extra_TruthCanonN_rec( nVarsReal <= 3? 3: nVarsReal, (unsigned char *)pt, pptRes, ppfRes, 0 ); + if ( nVarsMax == 6 && nVarsReal < nVarsMax ) + { + uTruthStore6[0] = **pptRes; + uTruthStore6[1] = **pptRes; + *pptRes = uTruthStore6; + } + return RetValue; +} + +/*---------------------------------------------------------------------------*/ +/* Definition of internal functions */ +/*---------------------------------------------------------------------------*/ + +/**Function************************************************************* + + Synopsis [Recursive implementation of the above.] + + Description [] + + SideEffects [This procedure has a bug, which shows on Solaris. + Most likely has something to do with the casts, i.g *((unsigned *)pt0)] + + SeeAlso [] + +***********************************************************************/ +int Extra_TruthCanonN_rec( int nVars, unsigned char * pt, unsigned ** pptRes, char ** ppfRes, int Flag ) +{ + static unsigned uTruthStore[7][2][2]; + static char uPhaseStore[7][2][64]; + + unsigned char * pt0, * pt1; + unsigned * ptRes0, * ptRes1, * ptRes; + unsigned uInit0, uInit1, uTruth0, uTruth1, uTemp; + char * pfRes0, * pfRes1, * pfRes; + int nf0, nf1, nfRes, i, nVarsN; + + // table lookup for three vars + if ( nVars == 3 ) + { + *pptRes = &s_Truths3[*pt]; + *ppfRes = s_Phases3[*pt]+1; + return s_Phases3[*pt][0]; + } + + // number of vars for the next call + nVarsN = nVars-1; + // truth table for the next call + pt0 = pt; + pt1 = pt + (1 << nVarsN) / 8; + // 5-var truth tables for this call +// uInit0 = *((unsigned *)pt0); +// uInit1 = *((unsigned *)pt1); + if ( nVarsN == 3 ) + { + uInit0 = (pt0[0] << 24) | (pt0[0] << 16) | (pt0[0] << 8) | pt0[0]; + uInit1 = (pt1[0] << 24) | (pt1[0] << 16) | (pt1[0] << 8) | pt1[0]; + } + else if ( nVarsN == 4 ) + { + uInit0 = (pt0[1] << 24) | (pt0[0] << 16) | (pt0[1] << 8) | pt0[0]; + uInit1 = (pt1[1] << 24) | (pt1[0] << 16) | (pt1[1] << 8) | pt1[0]; + } + else + { + uInit0 = (pt0[3] << 24) | (pt0[2] << 16) | (pt0[1] << 8) | pt0[0]; + uInit1 = (pt1[3] << 24) | (pt1[2] << 16) | (pt1[1] << 8) | pt1[0]; + } + + // storage for truth tables and phases + ptRes = uTruthStore[nVars][Flag]; + pfRes = uPhaseStore[nVars][Flag]; + + // solve trivial cases + if ( uInit1 == 0 ) + { + nf0 = Extra_TruthCanonN_rec( nVarsN, pt0, &ptRes0, &pfRes0, 0 ); + uTruth1 = uInit1; + uTruth0 = *ptRes0; + nfRes = 0; + for ( i = 0; i < nf0; i++ ) + pfRes[nfRes++] = pfRes0[i]; + goto finish; + } + if ( uInit0 == 0 ) + { + nf1 = Extra_TruthCanonN_rec( nVarsN, pt1, &ptRes1, &pfRes1, 1 ); + uTruth1 = uInit0; + uTruth0 = *ptRes1; + nfRes = 0; + for ( i = 0; i < nf1; i++ ) + pfRes[nfRes++] = pfRes1[i] | (1< uTemp ) + { + nfRes = 0; + uTruth0 = uTemp; + pfRes[nfRes++] = pfRes1[i]; + } + else if ( uTruth0 == uTemp ) + pfRes[nfRes++] = pfRes1[i]; + } + uTruth1 = *ptRes1; + } + else if ( *ptRes1 > *ptRes0 ) + { + uTruth0 = 0xFFFFFFFF; + nfRes = 0; + for ( i = 0; i < nf0; i++ ) + { + uTemp = Extra_TruthPolarize( uInit1, pfRes0[i], nVarsN ); + if ( uTruth0 > uTemp ) + { + nfRes = 0; + uTruth0 = uTemp; + pfRes[nfRes++] = pfRes0[i] | (1<= FileName; pDot-- ) + if ( *pDot == '.' ) + return pDot + 1; + return NULL; +} + +/**Function************************************************************* + + Synopsis [Returns the composite name of the file.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +char * Extra_FileNameAppend( char * pBase, char * pSuffix ) +{ + static char Buffer[500]; + sprintf( Buffer, "%s%s", pBase, pSuffix ); + return Buffer; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +char * Extra_FileNameGeneric( char * FileName ) +{ + char * pDot; + char * pUnd; + char * pRes; + + // find the generic name of the file + pRes = Extra_UtilStrsav( FileName ); + // find the pointer to the "." symbol in the file name +// pUnd = strstr( FileName, "_" ); + pUnd = NULL; + pDot = strstr( FileName, "." ); + if ( pUnd ) + pRes[pUnd - FileName] = 0; + else if ( pDot ) + pRes[pDot - FileName] = 0; + return pRes; +} + +/**Function************************************************************* + + Synopsis [Returns the file size.] + + Description [The file should be closed.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Extra_FileSize( char * pFileName ) +{ + FILE * pFile; + int nFileSize; + pFile = fopen( pFileName, "r" ); + if ( pFile == NULL ) + { + printf( "Extra_FileSize(): The file is unavailable (absent or open).\n" ); + return 0; + } + fseek( pFile, 0, SEEK_END ); + nFileSize = ftell( pFile ); + fclose( pFile ); + return nFileSize; +} + + +/**Function************************************************************* + + Synopsis [Read the file into the internal buffer.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +char * Extra_FileRead( FILE * pFile ) +{ + int nFileSize; + char * pBuffer; + // get the file size, in bytes + fseek( pFile, 0, SEEK_END ); + nFileSize = ftell( pFile ); + // move the file current reading position to the beginning + rewind( pFile ); + // load the contents of the file into memory + pBuffer = ALLOC( char, nFileSize + 3 ); + fread( pBuffer, nFileSize, 1, pFile ); + // terminate the string with '\0' + pBuffer[ nFileSize + 0] = '\n'; + pBuffer[ nFileSize + 1] = '\0'; + return pBuffer; +} + +/**Function************************************************************* + + Synopsis [Returns the time stamp.] + + Description [The file should be closed.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +char * Extra_TimeStamp() +{ + static char Buffer[100]; + char * TimeStamp; + time_t ltime; + // get the current time + time( <ime ); + TimeStamp = asctime( localtime( <ime ) ); + TimeStamp[ strlen(TimeStamp) - 1 ] = 0; + strcpy( Buffer, TimeStamp ); + return Buffer; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +unsigned Extra_ReadBinary( char * Buffer ) +{ + unsigned Result; + int i; + + Result = 0; + for ( i = 0; Buffer[i]; i++ ) + if ( Buffer[i] == '0' || Buffer[i] == '1' ) + Result = Result * 2 + Buffer[i] - '0'; + else + { + assert( 0 ); + } + return Result; +} + +/**Function************************************************************* + + Synopsis [Prints the bit string.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_PrintBinary( FILE * pFile, unsigned Sign[], int nBits ) +{ + int Remainder, nWords; + int w, i; + + Remainder = (nBits%(sizeof(unsigned)*8)); + nWords = (nBits/(sizeof(unsigned)*8)) + (Remainder>0); + + for ( w = nWords-1; w >= 0; w-- ) + for ( i = ((w == nWords-1 && Remainder)? Remainder-1: 31); i >= 0; i-- ) + fprintf( pFile, "%c", '0' + (int)((Sign[w] & (1< 0) ); + +// fprintf( pFile, "\n" ); +} + +/**Function************************************************************* + + Synopsis [Reads the hex unsigned into the bit-string.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Extra_ReadHexadecimal( unsigned Sign[], char * pString, int nVars ) +{ + int nWords, nDigits, Digit, k, c; + nWords = Extra_TruthWordNum( nVars ); + for ( k = 0; k < nWords; k++ ) + Sign[k] = 0; + // read the number from the string + nDigits = (1 << nVars) / 4; + if ( nDigits == 0 ) + nDigits = 1; + for ( k = 0; k < nDigits; k++ ) + { + c = nDigits-1-k; + if ( pString[c] >= '0' && pString[c] <= '9' ) + Digit = pString[c] - '0'; + else if ( pString[c] >= 'A' && pString[c] <= 'F' ) + Digit = pString[c] - 'A' + 10; + else if ( pString[c] >= 'a' && pString[c] <= 'f' ) + Digit = pString[c] - 'a' + 10; + else { assert( 0 ); return 0; } + Sign[k/8] |= ( (Digit & 15) << ((k%8) * 4) ); + } + return 1; +} + +/**Function************************************************************* + + Synopsis [Prints the hex unsigned into a file.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_PrintHexadecimal( FILE * pFile, unsigned Sign[], int nVars ) +{ + int nDigits, Digit, k; + // write the number into the file + nDigits = (1 << nVars) / 4; + for ( k = nDigits - 1; k >= 0; k-- ) + { + Digit = ((Sign[k/8] >> ((k%8) * 4)) & 15); + if ( Digit < 10 ) + fprintf( pFile, "%d", Digit ); + else + fprintf( pFile, "%c", 'a' + Digit-10 ); + } +// fprintf( pFile, "\n" ); +} + +/**Function************************************************************* + + Synopsis [Prints the hex unsigned into a file.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_PrintHexadecimalString( char * pString, unsigned Sign[], int nVars ) +{ + int nDigits, Digit, k; + // write the number into the file + nDigits = (1 << nVars) / 4; + for ( k = nDigits - 1; k >= 0; k-- ) + { + Digit = ((Sign[k/8] >> ((k%8) * 4)) & 15); + if ( Digit < 10 ) + *pString++ = '0' + Digit; + else + *pString++ = 'a' + Digit-10; + } +// fprintf( pFile, "\n" ); + *pString = 0; +} + +/**Function************************************************************* + + Synopsis [Prints the hex unsigned into a file.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_PrintHex( FILE * pFile, unsigned uTruth, int nVars ) +{ + int nMints, nDigits, Digit, k; + + // write the number into the file + fprintf( pFile, "0x" ); + nMints = (1 << nVars); + nDigits = nMints / 4; + for ( k = nDigits - 1; k >= 0; k-- ) + { + Digit = ((uTruth >> (k * 4)) & 15); + if ( Digit < 10 ) + fprintf( pFile, "%d", Digit ); + else + fprintf( pFile, "%c", 'a' + Digit-10 ); + } +// fprintf( pFile, "\n" ); +} + +/**Function************************************************************* + + Synopsis [Returns the composite name of the file.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_PrintSymbols( FILE * pFile, char Char, int nTimes, int fPrintNewLine ) +{ + int i; + for ( i = 0; i < nTimes; i++ ) + printf( "%c", Char ); + if ( fPrintNewLine ) + printf( "\n" ); +} + +/**Function************************************************************* + + Synopsis [Appends the string.] + + Description [Assumes that the given string (pStrGiven) has been allocated + before using malloc(). The additional string has not been allocated. + Allocs more root, appends the additional part, frees the old given string.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +char * Extra_StringAppend( char * pStrGiven, char * pStrAdd ) +{ + char * pTemp; + if ( pStrGiven ) + { + pTemp = ALLOC( char, strlen(pStrGiven) + strlen(pStrAdd) + 2 ); + sprintf( pTemp, "%s%s", pStrGiven, pStrAdd ); + free( pStrGiven ); + } + else + pTemp = Extra_UtilStrsav( pStrAdd ); + return pTemp; +} + +/*---------------------------------------------------------------------------*/ +/* Definition of internal functions */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Definition of static Functions */ +/*---------------------------------------------------------------------------*/ + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/misc/extra/extraUtilMemory.c b/src/misc/extra/extraUtilMemory.c new file mode 100644 index 00000000..6eccf015 --- /dev/null +++ b/src/misc/extra/extraUtilMemory.c @@ -0,0 +1,625 @@ +/**CFile**************************************************************** + + FileName [extraUtilMemory.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [extra] + + Synopsis [Memory managers.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: extraUtilMemory.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "extra.h" + +/*---------------------------------------------------------------------------*/ +/* Constant declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Stucture declarations */ +/*---------------------------------------------------------------------------*/ + +struct Extra_MmFixed_t_ +{ + // information about individual entries + int nEntrySize; // the size of one entry + int nEntriesAlloc; // the total number of entries allocated + int nEntriesUsed; // the number of entries in use + int nEntriesMax; // the max number of entries in use + char * pEntriesFree; // the linked list of free entries + + // this is where the memory is stored + int nChunkSize; // the size of one chunk + int nChunksAlloc; // the maximum number of memory chunks + int nChunks; // the current number of memory chunks + char ** pChunks; // the allocated memory + + // statistics + int nMemoryUsed; // memory used in the allocated entries + int nMemoryAlloc; // memory allocated +}; + +struct Extra_MmFlex_t_ +{ + // information about individual entries + int nEntriesUsed; // the number of entries allocated + char * pCurrent; // the current pointer to free memory + char * pEnd; // the first entry outside the free memory + + // this is where the memory is stored + int nChunkSize; // the size of one chunk + int nChunksAlloc; // the maximum number of memory chunks + int nChunks; // the current number of memory chunks + char ** pChunks; // the allocated memory + + // statistics + int nMemoryUsed; // memory used in the allocated entries + int nMemoryAlloc; // memory allocated +}; + + +struct Extra_MmStep_t_ +{ + int nMems; // the number of fixed memory managers employed + Extra_MmFixed_t ** pMems; // memory managers: 2^1 words, 2^2 words, etc + int nMapSize; // the size of the memory array + Extra_MmFixed_t ** pMap; // maps the number of bytes into its memory manager + int nLargeChunksAlloc; // the maximum number of large memory chunks + int nLargeChunks; // the current number of large memory chunks + void ** pLargeChunks; // the allocated large memory chunks +}; + +/*---------------------------------------------------------------------------*/ +/* Type declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Variable declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Macro declarations */ +/*---------------------------------------------------------------------------*/ + + +/**AutomaticStart*************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Static function prototypes */ +/*---------------------------------------------------------------------------*/ + +/**AutomaticEnd***************************************************************/ + + +/*---------------------------------------------------------------------------*/ +/* Definition of exported functions */ +/*---------------------------------------------------------------------------*/ + +/**Function************************************************************* + + Synopsis [Allocates memory pieces of fixed size.] + + Description [The size of the chunk is computed as the minimum of + 1024 entries and 64K. Can only work with entry size at least 4 byte long.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Extra_MmFixed_t * Extra_MmFixedStart( int nEntrySize ) +{ + Extra_MmFixed_t * p; + + p = ALLOC( Extra_MmFixed_t, 1 ); + memset( p, 0, sizeof(Extra_MmFixed_t) ); + + p->nEntrySize = nEntrySize; + p->nEntriesAlloc = 0; + p->nEntriesUsed = 0; + p->pEntriesFree = NULL; + + if ( nEntrySize * (1 << 10) < (1<<16) ) + p->nChunkSize = (1 << 10); + else + p->nChunkSize = (1<<16) / nEntrySize; + if ( p->nChunkSize < 8 ) + p->nChunkSize = 8; + + p->nChunksAlloc = 64; + p->nChunks = 0; + p->pChunks = ALLOC( char *, p->nChunksAlloc ); + + p->nMemoryUsed = 0; + p->nMemoryAlloc = 0; + return p; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_MmFixedPrint( Extra_MmFixed_t * p ) +{ + printf( "Fixed memory manager: Entry = %5d. Chunk = %5d. Chunks used = %5d.\n", + p->nEntrySize, p->nChunkSize, p->nChunks ); + printf( " Entries used = %8d. Entries peak = %8d. Memory used = %8d. Memory alloc = %8d.\n", + p->nEntriesUsed, p->nEntriesMax, p->nEntrySize * p->nEntriesUsed, p->nMemoryAlloc ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_MmFixedStop( Extra_MmFixed_t * p ) +{ + int i; + if ( p == NULL ) + return; + for ( i = 0; i < p->nChunks; i++ ) + free( p->pChunks[i] ); + free( p->pChunks ); + free( p ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +char * Extra_MmFixedEntryFetch( Extra_MmFixed_t * p ) +{ + char * pTemp; + int i; + + // check if there are still free entries + if ( p->nEntriesUsed == p->nEntriesAlloc ) + { // need to allocate more entries + assert( p->pEntriesFree == NULL ); + if ( p->nChunks == p->nChunksAlloc ) + { + p->nChunksAlloc *= 2; + p->pChunks = REALLOC( char *, p->pChunks, p->nChunksAlloc ); + } + p->pEntriesFree = ALLOC( char, p->nEntrySize * p->nChunkSize ); + p->nMemoryAlloc += p->nEntrySize * p->nChunkSize; + // transform these entries into a linked list + pTemp = p->pEntriesFree; + for ( i = 1; i < p->nChunkSize; i++ ) + { + *((char **)pTemp) = pTemp + p->nEntrySize; + pTemp += p->nEntrySize; + } + // set the last link + *((char **)pTemp) = NULL; + // add the chunk to the chunk storage + p->pChunks[ p->nChunks++ ] = p->pEntriesFree; + // add to the number of entries allocated + p->nEntriesAlloc += p->nChunkSize; + } + // incrememt the counter of used entries + p->nEntriesUsed++; + if ( p->nEntriesMax < p->nEntriesUsed ) + p->nEntriesMax = p->nEntriesUsed; + // return the first entry in the free entry list + pTemp = p->pEntriesFree; + p->pEntriesFree = *((char **)pTemp); + return pTemp; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_MmFixedEntryRecycle( Extra_MmFixed_t * p, char * pEntry ) +{ + // decrement the counter of used entries + p->nEntriesUsed--; + // add the entry to the linked list of free entries + *((char **)pEntry) = p->pEntriesFree; + p->pEntriesFree = pEntry; +} + +/**Function************************************************************* + + Synopsis [] + + Description [Relocates all the memory except the first chunk.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_MmFixedRestart( Extra_MmFixed_t * p ) +{ + int i; + char * pTemp; + + // deallocate all chunks except the first one + for ( i = 1; i < p->nChunks; i++ ) + free( p->pChunks[i] ); + p->nChunks = 1; + // transform these entries into a linked list + pTemp = p->pChunks[0]; + for ( i = 1; i < p->nChunkSize; i++ ) + { + *((char **)pTemp) = pTemp + p->nEntrySize; + pTemp += p->nEntrySize; + } + // set the last link + *((char **)pTemp) = NULL; + // set the free entry list + p->pEntriesFree = p->pChunks[0]; + // set the correct statistics + p->nMemoryAlloc = p->nEntrySize * p->nChunkSize; + p->nMemoryUsed = 0; + p->nEntriesAlloc = p->nChunkSize; + p->nEntriesUsed = 0; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Extra_MmFixedReadMemUsage( Extra_MmFixed_t * p ) +{ + return p->nMemoryAlloc; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Extra_MmFixedReadMaxEntriesUsed( Extra_MmFixed_t * p ) +{ + return p->nEntriesMax; +} + + +/**Function************************************************************* + + Synopsis [Allocates entries of flexible size.] + + Description [Can only work with entry size at least 4 byte long.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Extra_MmFlex_t * Extra_MmFlexStart() +{ + Extra_MmFlex_t * p; +//printf( "allocing flex\n" ); + p = ALLOC( Extra_MmFlex_t, 1 ); + memset( p, 0, sizeof(Extra_MmFlex_t) ); + + p->nEntriesUsed = 0; + p->pCurrent = NULL; + p->pEnd = NULL; + + p->nChunkSize = (1 << 10); + p->nChunksAlloc = 64; + p->nChunks = 0; + p->pChunks = ALLOC( char *, p->nChunksAlloc ); + + p->nMemoryUsed = 0; + p->nMemoryAlloc = 0; + return p; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_MmFlexPrint( Extra_MmFlex_t * p ) +{ + printf( "Flexible memory manager: Chunk size = %d. Chunks used = %d.\n", + p->nChunkSize, p->nChunks ); + printf( " Entries used = %d. Memory used = %d. Memory alloc = %d.\n", + p->nEntriesUsed, p->nMemoryUsed, p->nMemoryAlloc ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_MmFlexStop( Extra_MmFlex_t * p ) +{ + int i; + if ( p == NULL ) + return; +//printf( "deleting flex\n" ); + for ( i = 0; i < p->nChunks; i++ ) + free( p->pChunks[i] ); + free( p->pChunks ); + free( p ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +char * Extra_MmFlexEntryFetch( Extra_MmFlex_t * p, int nBytes ) +{ + char * pTemp; + // check if there are still free entries + if ( p->pCurrent == NULL || p->pCurrent + nBytes > p->pEnd ) + { // need to allocate more entries + if ( p->nChunks == p->nChunksAlloc ) + { + p->nChunksAlloc *= 2; + p->pChunks = REALLOC( char *, p->pChunks, p->nChunksAlloc ); + } + if ( nBytes > p->nChunkSize ) + { + // resize the chunk size if more memory is requested than it can give + // (ideally, this should never happen) + p->nChunkSize = 2 * nBytes; + } + p->pCurrent = ALLOC( char, p->nChunkSize ); + p->pEnd = p->pCurrent + p->nChunkSize; + p->nMemoryAlloc += p->nChunkSize; + // add the chunk to the chunk storage + p->pChunks[ p->nChunks++ ] = p->pCurrent; + } + assert( p->pCurrent + nBytes <= p->pEnd ); + // increment the counter of used entries + p->nEntriesUsed++; + // keep track of the memory used + p->nMemoryUsed += nBytes; + // return the next entry + pTemp = p->pCurrent; + p->pCurrent += nBytes; + return pTemp; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Extra_MmFlexReadMemUsage( Extra_MmFlex_t * p ) +{ + return p->nMemoryAlloc; +} + + + + + +/**Function************************************************************* + + Synopsis [Starts the hierarchical memory manager.] + + Description [This manager can allocate entries of any size. + Iternally they are mapped into the entries with the number of bytes + equal to the power of 2. The smallest entry size is 8 bytes. The + next one is 16 bytes etc. So, if the user requests 6 bytes, he gets + 8 byte entry. If we asks for 25 bytes, he gets 32 byte entry etc. + The input parameters "nSteps" says how many fixed memory managers + are employed internally. Calling this procedure with nSteps equal + to 10 results in 10 hierarchically arranged internal memory managers, + which can allocate up to 4096 (1Kb) entries. Requests for larger + entries are handed over to malloc() and then free()ed.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Extra_MmStep_t * Extra_MmStepStart( int nSteps ) +{ + Extra_MmStep_t * p; + int i, k; + p = ALLOC( Extra_MmStep_t, 1 ); + memset( p, 0, sizeof(Extra_MmStep_t) ); + p->nMems = nSteps; + // start the fixed memory managers + p->pMems = ALLOC( Extra_MmFixed_t *, p->nMems ); + for ( i = 0; i < p->nMems; i++ ) + p->pMems[i] = Extra_MmFixedStart( (8<nMapSize = (4<nMems); + p->pMap = ALLOC( Extra_MmFixed_t *, p->nMapSize+1 ); + p->pMap[0] = NULL; + for ( k = 1; k <= 4; k++ ) + p->pMap[k] = p->pMems[0]; + for ( i = 0; i < p->nMems; i++ ) + for ( k = (4<pMap[k] = p->pMems[i]; +//for ( i = 1; i < 100; i ++ ) +//printf( "%10d: size = %10d\n", i, p->pMap[i]->nEntrySize ); + return p; +} + +/**Function************************************************************* + + Synopsis [Stops the memory manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_MmStepStop( Extra_MmStep_t * p ) +{ + int i; + for ( i = 0; i < p->nMems; i++ ) + Extra_MmFixedStop( p->pMems[i] ); +// if ( p->pLargeChunks ) +// { +// for ( i = 0; i < p->nLargeChunks; i++ ) +// free( p->pLargeChunks[i] ); +// free( p->pLargeChunks ); +// } + free( p->pMems ); + free( p->pMap ); + free( p ); +} + +/**Function************************************************************* + + Synopsis [Creates the entry.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +char * Extra_MmStepEntryFetch( Extra_MmStep_t * p, int nBytes ) +{ + if ( nBytes == 0 ) + return NULL; + if ( nBytes > p->nMapSize ) + { +// printf( "Allocating %d bytes.\n", nBytes ); +/* + if ( p->nLargeChunks == p->nLargeChunksAlloc ) + { + if ( p->nLargeChunksAlloc == 0 ) + p->nLargeChunksAlloc = 5; + p->nLargeChunksAlloc *= 2; + p->pLargeChunks = REALLOC( char *, p->pLargeChunks, p->nLargeChunksAlloc ); + } + p->pLargeChunks[ p->nLargeChunks++ ] = ALLOC( char, nBytes ); + return p->pLargeChunks[ p->nLargeChunks - 1 ]; +*/ + return ALLOC( char, nBytes ); + } + return Extra_MmFixedEntryFetch( p->pMap[nBytes] ); +} + + +/**Function************************************************************* + + Synopsis [Recycles the entry.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_MmStepEntryRecycle( Extra_MmStep_t * p, char * pEntry, int nBytes ) +{ + if ( nBytes == 0 ) + return; + if ( nBytes > p->nMapSize ) + { + free( pEntry ); + return; + } + Extra_MmFixedEntryRecycle( p->pMap[nBytes], pEntry ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Extra_MmStepReadMemUsage( Extra_MmStep_t * p ) +{ + int i, nMemTotal = 0; + for ( i = 0; i < p->nMems; i++ ) + nMemTotal += p->pMems[i]->nMemoryAlloc; + return nMemTotal; +} + +/*---------------------------------------------------------------------------*/ +/* Definition of internal functions */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Definition of static functions */ +/*---------------------------------------------------------------------------*/ + diff --git a/src/misc/extra/extraUtilMisc.c b/src/misc/extra/extraUtilMisc.c new file mode 100644 index 00000000..dff774bc --- /dev/null +++ b/src/misc/extra/extraUtilMisc.c @@ -0,0 +1,2235 @@ +/**CFile**************************************************************** + + FileName [extraUtilMisc.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [extra] + + Synopsis [Misc procedures.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: extraUtilMisc.c,v 1.0 2003/09/01 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "extra.h" + +/*---------------------------------------------------------------------------*/ +/* Constant declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Stucture declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Type declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Variable declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Macro declarations */ +/*---------------------------------------------------------------------------*/ + + +/**AutomaticStart*************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Static function prototypes */ +/*---------------------------------------------------------------------------*/ + +/**AutomaticEnd***************************************************************/ + +static void Extra_Permutations_rec( char ** pRes, int nFact, int n, char Array[] ); + +/*---------------------------------------------------------------------------*/ +/* Definition of exported functions */ +/*---------------------------------------------------------------------------*/ + + +/**Function******************************************************************** + + Synopsis [Finds the smallest integer larger of equal than the logarithm.] + + Description [Returns [Log2(Num)].] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +int Extra_Base2Log( unsigned Num ) +{ + int Res; + assert( Num >= 0 ); + if ( Num == 0 ) return 0; + if ( Num == 1 ) return 1; + for ( Res = 0, Num--; Num; Num >>= 1, Res++ ); + return Res; +} /* end of Extra_Base2Log */ + +/**Function******************************************************************** + + Synopsis [Finds the smallest integer larger of equal than the logarithm.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +int Extra_Base2LogDouble( double Num ) +{ + double Res; + int ResInt; + + Res = log(Num)/log(2.0); + ResInt = (int)Res; + if ( ResInt == Res ) + return ResInt; + else + return ResInt+1; +} + +/**Function******************************************************************** + + Synopsis [Finds the smallest integer larger of equal than the logarithm.] + + Description [Returns [Log10(Num)].] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +int Extra_Base10Log( unsigned Num ) +{ + int Res; + assert( Num >= 0 ); + if ( Num == 0 ) return 0; + if ( Num == 1 ) return 1; + for ( Res = 0, Num--; Num; Num /= 10, Res++ ); + return Res; +} /* end of Extra_Base2Log */ + +/**Function******************************************************************** + + Synopsis [Returns the power of two as a double.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +double Extra_Power2( int Degree ) +{ + double Res; + assert( Degree >= 0 ); + if ( Degree < 32 ) + return (double)(01<>= Shift; + uTruth = uCof0 | uCof1; + } + return uTruth; +} + +/**Function************************************************************* + + Synopsis [Computes N-canonical form using brute-force methods.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +unsigned Extra_TruthCanonN( unsigned uTruth, int nVars ) +{ + unsigned uTruthMin, uPhase; + int nMints, i; + nMints = (1 << nVars); + uTruthMin = 0xFFFFFFFF; + for ( i = 0; i < nMints; i++ ) + { + uPhase = Extra_TruthPolarize( uTruth, i, nVars ); + if ( uTruthMin > uPhase ) + uTruthMin = uPhase; + } + return uTruthMin; +} + +/**Function************************************************************* + + Synopsis [Computes NN-canonical form using brute-force methods.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +unsigned Extra_TruthCanonNN( unsigned uTruth, int nVars ) +{ + unsigned uTruthMin, uTruthC, uPhase; + int nMints, i; + nMints = (1 << nVars); + uTruthC = (unsigned)( (~uTruth) & ((~((unsigned)0)) >> (32-nMints)) ); + uTruthMin = 0xFFFFFFFF; + for ( i = 0; i < nMints; i++ ) + { + uPhase = Extra_TruthPolarize( uTruth, i, nVars ); + if ( uTruthMin > uPhase ) + uTruthMin = uPhase; + uPhase = Extra_TruthPolarize( uTruthC, i, nVars ); + if ( uTruthMin > uPhase ) + uTruthMin = uPhase; + } + return uTruthMin; +} + +/**Function************************************************************* + + Synopsis [Computes P-canonical form using brute-force methods.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +unsigned Extra_TruthCanonP( unsigned uTruth, int nVars ) +{ + static int nVarsOld, nPerms; + static char ** pPerms = NULL; + + unsigned uTruthMin, uPerm; + int k; + + if ( pPerms == NULL ) + { + nPerms = Extra_Factorial( nVars ); + pPerms = Extra_Permutations( nVars ); + nVarsOld = nVars; + } + else if ( nVarsOld != nVars ) + { + free( pPerms ); + nPerms = Extra_Factorial( nVars ); + pPerms = Extra_Permutations( nVars ); + nVarsOld = nVars; + } + + uTruthMin = 0xFFFFFFFF; + for ( k = 0; k < nPerms; k++ ) + { + uPerm = Extra_TruthPermute( uTruth, pPerms[k], nVars, 0 ); + if ( uTruthMin > uPerm ) + uTruthMin = uPerm; + } + return uTruthMin; +} + +/**Function************************************************************* + + Synopsis [Computes NP-canonical form using brute-force methods.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +unsigned Extra_TruthCanonNP( unsigned uTruth, int nVars ) +{ + static int nVarsOld, nPerms; + static char ** pPerms = NULL; + + unsigned uTruthMin, uPhase, uPerm; + int nMints, k, i; + + if ( pPerms == NULL ) + { + nPerms = Extra_Factorial( nVars ); + pPerms = Extra_Permutations( nVars ); + nVarsOld = nVars; + } + else if ( nVarsOld != nVars ) + { + free( pPerms ); + nPerms = Extra_Factorial( nVars ); + pPerms = Extra_Permutations( nVars ); + nVarsOld = nVars; + } + + nMints = (1 << nVars); + uTruthMin = 0xFFFFFFFF; + for ( i = 0; i < nMints; i++ ) + { + uPhase = Extra_TruthPolarize( uTruth, i, nVars ); + for ( k = 0; k < nPerms; k++ ) + { + uPerm = Extra_TruthPermute( uPhase, pPerms[k], nVars, 0 ); + if ( uTruthMin > uPerm ) + uTruthMin = uPerm; + } + } + return uTruthMin; +} + +/**Function************************************************************* + + Synopsis [Computes NPN-canonical form using brute-force methods.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +unsigned Extra_TruthCanonNPN( unsigned uTruth, int nVars ) +{ + static int nVarsOld, nPerms; + static char ** pPerms = NULL; + + unsigned uTruthMin, uTruthC, uPhase, uPerm; + int nMints, k, i; + + if ( pPerms == NULL ) + { + nPerms = Extra_Factorial( nVars ); + pPerms = Extra_Permutations( nVars ); + nVarsOld = nVars; + } + else if ( nVarsOld != nVars ) + { + free( pPerms ); + nPerms = Extra_Factorial( nVars ); + pPerms = Extra_Permutations( nVars ); + nVarsOld = nVars; + } + + nMints = (1 << nVars); + uTruthC = (unsigned)( (~uTruth) & ((~((unsigned)0)) >> (32-nMints)) ); + uTruthMin = 0xFFFFFFFF; + for ( i = 0; i < nMints; i++ ) + { + uPhase = Extra_TruthPolarize( uTruth, i, nVars ); + for ( k = 0; k < nPerms; k++ ) + { + uPerm = Extra_TruthPermute( uPhase, pPerms[k], nVars, 0 ); + if ( uTruthMin > uPerm ) + uTruthMin = uPerm; + } + uPhase = Extra_TruthPolarize( uTruthC, i, nVars ); + for ( k = 0; k < nPerms; k++ ) + { + uPerm = Extra_TruthPermute( uPhase, pPerms[k], nVars, 0 ); + if ( uTruthMin > uPerm ) + uTruthMin = uPerm; + } + } + return uTruthMin; +} + +/**Function************************************************************* + + Synopsis [Computes NPN canonical forms for 4-variable functions.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_Truth4VarNPN( unsigned short ** puCanons, char ** puPhases, char ** puPerms, unsigned char ** puMap ) +{ + unsigned short * uCanons; + unsigned char * uMap; + unsigned uTruth, uPhase, uPerm; + char ** pPerms4, * uPhases, * uPerms; + int nFuncs, nClasses; + int i, k; + + nFuncs = (1 << 16); + uCanons = ALLOC( unsigned short, nFuncs ); + uPhases = ALLOC( char, nFuncs ); + uPerms = ALLOC( char, nFuncs ); + uMap = ALLOC( unsigned char, nFuncs ); + memset( uCanons, 0, sizeof(unsigned short) * nFuncs ); + memset( uPhases, 0, sizeof(char) * nFuncs ); + memset( uPerms, 0, sizeof(char) * nFuncs ); + memset( uMap, 0, sizeof(unsigned char) * nFuncs ); + pPerms4 = Extra_Permutations( 4 ); + + nClasses = 1; + nFuncs = (1 << 15); + for ( uTruth = 1; uTruth < (unsigned)nFuncs; uTruth++ ) + { + // skip already assigned + if ( uCanons[uTruth] ) + { + assert( uTruth > uCanons[uTruth] ); + uMap[~uTruth & 0xFFFF] = uMap[uTruth] = uMap[uCanons[uTruth]]; + continue; + } + uMap[uTruth] = nClasses++; + for ( i = 0; i < 16; i++ ) + { + uPhase = Extra_TruthPolarize( uTruth, i, 4 ); + for ( k = 0; k < 24; k++ ) + { + uPerm = Extra_TruthPermute( uPhase, pPerms4[k], 4, 0 ); + if ( uCanons[uPerm] == 0 ) + { + uCanons[uPerm] = uTruth; + uPhases[uPerm] = i; + uPerms[uPerm] = k; + + uPerm = ~uPerm & 0xFFFF; + uCanons[uPerm] = uTruth; + uPhases[uPerm] = i | 16; + uPerms[uPerm] = k; + } + else + assert( uCanons[uPerm] == uTruth ); + } + uPhase = Extra_TruthPolarize( ~uTruth & 0xFFFF, i, 4 ); + for ( k = 0; k < 24; k++ ) + { + uPerm = Extra_TruthPermute( uPhase, pPerms4[k], 4, 0 ); + if ( uCanons[uPerm] == 0 ) + { + uCanons[uPerm] = uTruth; + uPhases[uPerm] = i; + uPerms[uPerm] = k; + + uPerm = ~uPerm & 0xFFFF; + uCanons[uPerm] = uTruth; + uPhases[uPerm] = i | 16; + uPerms[uPerm] = k; + } + else + assert( uCanons[uPerm] == uTruth ); + } + } + } + uPhases[(1<<16)-1] = 16; + assert( nClasses == 222 ); + free( pPerms4 ); + if ( puCanons ) + *puCanons = uCanons; + else + free( uCanons ); + if ( puPhases ) + *puPhases = uPhases; + else + free( uPhases ); + if ( puPerms ) + *puPerms = uPerms; + else + free( uPerms ); + if ( puMap ) + *puMap = uMap; + else + free( uMap ); +} + +/**Function************************************************************* + + Synopsis [Computes NPN canonical forms for 4-variable functions.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_Truth3VarN( unsigned ** puCanons, char *** puPhases, char ** ppCounters ) +{ + int nPhasesMax = 8; + unsigned * uCanons; + unsigned uTruth, uPhase, uTruth32; + char ** uPhases, * pCounters; + int nFuncs, nClasses, i; + + nFuncs = (1 << 8); + uCanons = ALLOC( unsigned, nFuncs ); + memset( uCanons, 0, sizeof(unsigned) * nFuncs ); + pCounters = ALLOC( char, nFuncs ); + memset( pCounters, 0, sizeof(char) * nFuncs ); + uPhases = (char **)Extra_ArrayAlloc( nFuncs, nPhasesMax, sizeof(char) ); + nClasses = 0; + for ( uTruth = 0; uTruth < (unsigned)nFuncs; uTruth++ ) + { + // skip already assigned + uTruth32 = ((uTruth << 24) | (uTruth << 16) | (uTruth << 8) | uTruth); + if ( uCanons[uTruth] ) + { + assert( uTruth32 > uCanons[uTruth] ); + continue; + } + nClasses++; + for ( i = 0; i < 8; i++ ) + { + uPhase = Extra_TruthPolarize( uTruth, i, 3 ); + if ( uCanons[uPhase] == 0 && (uTruth || i==0) ) + { + uCanons[uPhase] = uTruth32; + uPhases[uPhase][0] = i; + pCounters[uPhase] = 1; + } + else + { + assert( uCanons[uPhase] == uTruth32 ); + if ( pCounters[uPhase] < nPhasesMax ) + uPhases[uPhase][ pCounters[uPhase]++ ] = i; + } + } + } + if ( puCanons ) + *puCanons = uCanons; + else + free( uCanons ); + if ( puPhases ) + *puPhases = uPhases; + else + free( uPhases ); + if ( ppCounters ) + *ppCounters = pCounters; + else + free( pCounters ); +// printf( "The number of 3N-classes = %d.\n", nClasses ); +} + +/**Function************************************************************* + + Synopsis [Computes NPN canonical forms for 4-variable functions.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_Truth4VarN( unsigned short ** puCanons, char *** puPhases, char ** ppCounters, int nPhasesMax ) +{ + unsigned short * uCanons; + unsigned uTruth, uPhase; + char ** uPhases, * pCounters; + int nFuncs, nClasses, i; + + nFuncs = (1 << 16); + uCanons = ALLOC( unsigned short, nFuncs ); + memset( uCanons, 0, sizeof(unsigned short) * nFuncs ); + pCounters = ALLOC( char, nFuncs ); + memset( pCounters, 0, sizeof(char) * nFuncs ); + uPhases = (char **)Extra_ArrayAlloc( nFuncs, nPhasesMax, sizeof(char) ); + nClasses = 0; + for ( uTruth = 0; uTruth < (unsigned)nFuncs; uTruth++ ) + { + // skip already assigned + if ( uCanons[uTruth] ) + { + assert( uTruth > uCanons[uTruth] ); + continue; + } + nClasses++; + for ( i = 0; i < 16; i++ ) + { + uPhase = Extra_TruthPolarize( uTruth, i, 4 ); + if ( uCanons[uPhase] == 0 && (uTruth || i==0) ) + { + uCanons[uPhase] = uTruth; + uPhases[uPhase][0] = i; + pCounters[uPhase] = 1; + } + else + { + assert( uCanons[uPhase] == uTruth ); + if ( pCounters[uPhase] < nPhasesMax ) + uPhases[uPhase][ pCounters[uPhase]++ ] = i; + } + } + } + if ( puCanons ) + *puCanons = uCanons; + else + free( uCanons ); + if ( puPhases ) + *puPhases = uPhases; + else + free( uPhases ); + if ( ppCounters ) + *ppCounters = pCounters; + else + free( pCounters ); +// printf( "The number of 4N-classes = %d.\n", nClasses ); +} + +/**Function************************************************************* + + Synopsis [Allocated one-memory-chunk array.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void ** Extra_ArrayAlloc( int nCols, int nRows, int Size ) +{ + char ** pRes; + char * pBuffer; + int i; + assert( nCols > 0 && nRows > 0 && Size > 0 ); + pBuffer = ALLOC( char, nCols * (sizeof(void *) + nRows * Size) ); + pRes = (char **)pBuffer; + pRes[0] = pBuffer + nCols * sizeof(void *); + for ( i = 1; i < nCols; i++ ) + pRes[i] = pRes[0] + i * nRows * Size; + return pRes; +} + +/**Function************************************************************* + + Synopsis [Computes a phase of the 3-var function.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +unsigned short Extra_TruthPerm4One( unsigned uTruth, int Phase ) +{ + // cases + static unsigned short Cases[16] = { + 0, // 0000 - skip + 0, // 0001 - skip + 0xCCCC, // 0010 - single var + 0, // 0011 - skip + 0xF0F0, // 0100 - single var + 1, // 0101 + 1, // 0110 + 0, // 0111 - skip + 0xFF00, // 1000 - single var + 1, // 1001 + 1, // 1010 + 1, // 1011 + 1, // 1100 + 1, // 1101 + 1, // 1110 + 0 // 1111 - skip + }; + // permutations + static int Perms[16][4] = { + { 0, 0, 0, 0 }, // 0000 - skip + { 0, 0, 0, 0 }, // 0001 - skip + { 0, 0, 0, 0 }, // 0010 - single var + { 0, 0, 0, 0 }, // 0011 - skip + { 0, 0, 0, 0 }, // 0100 - single var + { 0, 2, 1, 3 }, // 0101 + { 2, 0, 1, 3 }, // 0110 + { 0, 0, 0, 0 }, // 0111 - skip + { 0, 0, 0, 0 }, // 1000 - single var + { 0, 2, 3, 1 }, // 1001 + { 2, 0, 3, 1 }, // 1010 + { 0, 1, 3, 2 }, // 1011 + { 2, 3, 0, 1 }, // 1100 + { 0, 3, 1, 2 }, // 1101 + { 3, 0, 1, 2 }, // 1110 + { 0, 0, 0, 0 } // 1111 - skip + }; + int i, k, iRes; + unsigned uTruthRes; + assert( Phase >= 0 && Phase < 16 ); + if ( Cases[Phase] == 0 ) + return uTruth; + if ( Cases[Phase] > 1 ) + return Cases[Phase]; + uTruthRes = 0; + for ( i = 0; i < 16; i++ ) + if ( uTruth & (1 << i) ) + { + for ( iRes = 0, k = 0; k < 4; k++ ) + if ( i & (1 << Perms[Phase][k]) ) + iRes |= (1 << k); + uTruthRes |= (1 << iRes); + } + return uTruthRes; +} + +/**Function************************************************************* + + Synopsis [Computes a phase of the 3-var function.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +unsigned Extra_TruthPerm5One( unsigned uTruth, int Phase ) +{ + // cases + static unsigned Cases[32] = { + 0, // 00000 - skip + 0, // 00001 - skip + 0xCCCCCCCC, // 00010 - single var + 0, // 00011 - skip + 0xF0F0F0F0, // 00100 - single var + 1, // 00101 + 1, // 00110 + 0, // 00111 - skip + 0xFF00FF00, // 01000 - single var + 1, // 01001 + 1, // 01010 + 1, // 01011 + 1, // 01100 + 1, // 01101 + 1, // 01110 + 0, // 01111 - skip + 0xFFFF0000, // 10000 - skip + 1, // 10001 + 1, // 10010 + 1, // 10011 + 1, // 10100 + 1, // 10101 + 1, // 10110 + 1, // 10111 - four var + 1, // 11000 + 1, // 11001 + 1, // 11010 + 1, // 11011 - four var + 1, // 11100 + 1, // 11101 - four var + 1, // 11110 - four var + 0 // 11111 - skip + }; + // permutations + static int Perms[32][5] = { + { 0, 0, 0, 0, 0 }, // 00000 - skip + { 0, 0, 0, 0, 0 }, // 00001 - skip + { 0, 0, 0, 0, 0 }, // 00010 - single var + { 0, 0, 0, 0, 0 }, // 00011 - skip + { 0, 0, 0, 0, 0 }, // 00100 - single var + { 0, 2, 1, 3, 4 }, // 00101 + { 2, 0, 1, 3, 4 }, // 00110 + { 0, 0, 0, 0, 0 }, // 00111 - skip + { 0, 0, 0, 0, 0 }, // 01000 - single var + { 0, 2, 3, 1, 4 }, // 01001 + { 2, 0, 3, 1, 4 }, // 01010 + { 0, 1, 3, 2, 4 }, // 01011 + { 2, 3, 0, 1, 4 }, // 01100 + { 0, 3, 1, 2, 4 }, // 01101 + { 3, 0, 1, 2, 4 }, // 01110 + { 0, 0, 0, 0, 0 }, // 01111 - skip + { 0, 0, 0, 0, 0 }, // 10000 - single var + { 0, 4, 2, 3, 1 }, // 10001 + { 4, 0, 2, 3, 1 }, // 10010 + { 0, 1, 3, 4, 2 }, // 10011 + { 2, 3, 0, 4, 1 }, // 10100 + { 0, 3, 1, 4, 2 }, // 10101 + { 3, 0, 1, 4, 2 }, // 10110 + { 0, 1, 2, 4, 3 }, // 10111 - four var + { 2, 3, 4, 0, 1 }, // 11000 + { 0, 3, 4, 1, 2 }, // 11001 + { 3, 0, 4, 1, 2 }, // 11010 + { 0, 1, 4, 2, 3 }, // 11011 - four var + { 3, 4, 0, 1, 2 }, // 11100 + { 0, 4, 1, 2, 3 }, // 11101 - four var + { 4, 0, 1, 2, 3 }, // 11110 - four var + { 0, 0, 0, 0, 0 } // 11111 - skip + }; + int i, k, iRes; + unsigned uTruthRes; + assert( Phase >= 0 && Phase < 32 ); + if ( Cases[Phase] == 0 ) + return uTruth; + if ( Cases[Phase] > 1 ) + return Cases[Phase]; + uTruthRes = 0; + for ( i = 0; i < 32; i++ ) + if ( uTruth & (1 << i) ) + { + for ( iRes = 0, k = 0; k < 5; k++ ) + if ( i & (1 << Perms[Phase][k]) ) + iRes |= (1 << k); + uTruthRes |= (1 << iRes); + } + return uTruthRes; +} + +/**Function************************************************************* + + Synopsis [Computes a phase of the 3-var function.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_TruthPerm6One( unsigned * uTruth, int Phase, unsigned * uTruthRes ) +{ + // cases + static unsigned Cases[64] = { + 0, // 000000 - skip + 0, // 000001 - skip + 0xCCCCCCCC, // 000010 - single var + 0, // 000011 - skip + 0xF0F0F0F0, // 000100 - single var + 1, // 000101 + 1, // 000110 + 0, // 000111 - skip + 0xFF00FF00, // 001000 - single var + 1, // 001001 + 1, // 001010 + 1, // 001011 + 1, // 001100 + 1, // 001101 + 1, // 001110 + 0, // 001111 - skip + 0xFFFF0000, // 010000 - skip + 1, // 010001 + 1, // 010010 + 1, // 010011 + 1, // 010100 + 1, // 010101 + 1, // 010110 + 1, // 010111 - four var + 1, // 011000 + 1, // 011001 + 1, // 011010 + 1, // 011011 - four var + 1, // 011100 + 1, // 011101 - four var + 1, // 011110 - four var + 0, // 011111 - skip + 0xFFFFFFFF, // 100000 - single var + 1, // 100001 + 1, // 100010 + 1, // 100011 + 1, // 100100 + 1, // 100101 + 1, // 100110 + 1, // 100111 + 1, // 101000 + 1, // 101001 + 1, // 101010 + 1, // 101011 + 1, // 101100 + 1, // 101101 + 1, // 101110 + 1, // 101111 + 1, // 110000 + 1, // 110001 + 1, // 110010 + 1, // 110011 + 1, // 110100 + 1, // 110101 + 1, // 110110 + 1, // 110111 + 1, // 111000 + 1, // 111001 + 1, // 111010 + 1, // 111011 + 1, // 111100 + 1, // 111101 + 1, // 111110 + 0 // 111111 - skip + }; + // permutations + static int Perms[64][6] = { + { 0, 0, 0, 0, 0, 0 }, // 000000 - skip + { 0, 0, 0, 0, 0, 0 }, // 000001 - skip + { 0, 0, 0, 0, 0, 0 }, // 000010 - single var + { 0, 0, 0, 0, 0, 0 }, // 000011 - skip + { 0, 0, 0, 0, 0, 0 }, // 000100 - single var + { 0, 2, 1, 3, 4, 5 }, // 000101 + { 2, 0, 1, 3, 4, 5 }, // 000110 + { 0, 0, 0, 0, 0, 0 }, // 000111 - skip + { 0, 0, 0, 0, 0, 0 }, // 001000 - single var + { 0, 2, 3, 1, 4, 5 }, // 001001 + { 2, 0, 3, 1, 4, 5 }, // 001010 + { 0, 1, 3, 2, 4, 5 }, // 001011 + { 2, 3, 0, 1, 4, 5 }, // 001100 + { 0, 3, 1, 2, 4, 5 }, // 001101 + { 3, 0, 1, 2, 4, 5 }, // 001110 + { 0, 0, 0, 0, 0, 0 }, // 001111 - skip + { 0, 0, 0, 0, 0, 0 }, // 010000 - skip + { 0, 4, 2, 3, 1, 5 }, // 010001 + { 4, 0, 2, 3, 1, 5 }, // 010010 + { 0, 1, 3, 4, 2, 5 }, // 010011 + { 2, 3, 0, 4, 1, 5 }, // 010100 + { 0, 3, 1, 4, 2, 5 }, // 010101 + { 3, 0, 1, 4, 2, 5 }, // 010110 + { 0, 1, 2, 4, 3, 5 }, // 010111 - four var + { 2, 3, 4, 0, 1, 5 }, // 011000 + { 0, 3, 4, 1, 2, 5 }, // 011001 + { 3, 0, 4, 1, 2, 5 }, // 011010 + { 0, 1, 4, 2, 3, 5 }, // 011011 - four var + { 3, 4, 0, 1, 2, 5 }, // 011100 + { 0, 4, 1, 2, 3, 5 }, // 011101 - four var + { 4, 0, 1, 2, 3, 5 }, // 011110 - four var + { 0, 0, 0, 0, 0, 0 }, // 011111 - skip + { 0, 0, 0, 0, 0, 0 }, // 100000 - single var + { 0, 2, 3, 4, 5, 1 }, // 100001 + { 2, 0, 3, 4, 5, 1 }, // 100010 + { 0, 1, 3, 4, 5, 2 }, // 100011 + { 2, 3, 0, 4, 5, 1 }, // 100100 + { 0, 3, 1, 4, 5, 2 }, // 100101 + { 3, 0, 1, 4, 5, 2 }, // 100110 + { 0, 1, 2, 4, 5, 3 }, // 100111 + { 2, 3, 4, 0, 5, 1 }, // 101000 + { 0, 3, 4, 1, 5, 2 }, // 101001 + { 3, 0, 4, 1, 5, 2 }, // 101010 + { 0, 1, 4, 2, 5, 3 }, // 101011 + { 3, 4, 0, 1, 5, 2 }, // 101100 + { 0, 4, 1, 2, 5, 3 }, // 101101 + { 4, 0, 1, 2, 5, 3 }, // 101110 + { 0, 1, 2, 3, 5, 4 }, // 101111 + { 2, 3, 4, 5, 0, 1 }, // 110000 + { 0, 3, 4, 5, 1, 2 }, // 110001 + { 3, 0, 4, 5, 1, 2 }, // 110010 + { 0, 1, 4, 5, 2, 3 }, // 110011 + { 3, 4, 0, 5, 1, 2 }, // 110100 + { 0, 4, 1, 5, 2, 3 }, // 110101 + { 4, 0, 1, 5, 2, 3 }, // 110110 + { 0, 1, 2, 5, 3, 4 }, // 110111 + { 3, 4, 5, 0, 1, 2 }, // 111000 + { 0, 4, 5, 1, 2, 3 }, // 111001 + { 4, 0, 5, 1, 2, 3 }, // 111010 + { 0, 1, 5, 2, 3, 4 }, // 111011 + { 4, 5, 0, 1, 2, 3 }, // 111100 + { 0, 5, 1, 2, 3, 4 }, // 111101 + { 5, 0, 1, 2, 3, 4 }, // 111110 + { 0, 0, 0, 0, 0, 0 } // 111111 - skip + }; + int i, k, iRes; + assert( Phase >= 0 && Phase < 64 ); + if ( Cases[Phase] == 0 ) + { + uTruthRes[0] = uTruth[0]; + uTruthRes[1] = uTruth[1]; + return; + } + if ( Cases[Phase] > 1 ) + { + if ( Phase == 32 ) + { + uTruthRes[0] = 0x00000000; + uTruthRes[1] = 0xFFFFFFFF; + } + else + { + uTruthRes[0] = Cases[Phase]; + uTruthRes[1] = Cases[Phase]; + } + return; + } + uTruthRes[0] = 0; + uTruthRes[1] = 0; + for ( i = 0; i < 64; i++ ) + { + if ( i < 32 ) + { + if ( uTruth[0] & (1 << i) ) + { + for ( iRes = 0, k = 0; k < 6; k++ ) + if ( i & (1 << Perms[Phase][k]) ) + iRes |= (1 << k); + if ( iRes < 32 ) + uTruthRes[0] |= (1 << iRes); + else + uTruthRes[1] |= (1 << (iRes-32)); + } + } + else + { + if ( uTruth[1] & (1 << (i-32)) ) + { + for ( iRes = 0, k = 0; k < 6; k++ ) + if ( i & (1 << Perms[Phase][k]) ) + iRes |= (1 << k); + if ( iRes < 32 ) + uTruthRes[0] |= (1 << iRes); + else + uTruthRes[1] |= (1 << (iRes-32)); + } + } + } +} + +/**Function************************************************************* + + Synopsis [Computes a phase of the 8-var function.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_TruthExpand( int nVars, int nWords, unsigned * puTruth, unsigned uPhase, unsigned * puTruthR ) +{ + // elementary truth tables + static unsigned uTruths[8][8] = { + { 0xAAAAAAAA,0xAAAAAAAA,0xAAAAAAAA,0xAAAAAAAA,0xAAAAAAAA,0xAAAAAAAA,0xAAAAAAAA,0xAAAAAAAA }, + { 0xCCCCCCCC,0xCCCCCCCC,0xCCCCCCCC,0xCCCCCCCC,0xCCCCCCCC,0xCCCCCCCC,0xCCCCCCCC,0xCCCCCCCC }, + { 0xF0F0F0F0,0xF0F0F0F0,0xF0F0F0F0,0xF0F0F0F0,0xF0F0F0F0,0xF0F0F0F0,0xF0F0F0F0,0xF0F0F0F0 }, + { 0xFF00FF00,0xFF00FF00,0xFF00FF00,0xFF00FF00,0xFF00FF00,0xFF00FF00,0xFF00FF00,0xFF00FF00 }, + { 0xFFFF0000,0xFFFF0000,0xFFFF0000,0xFFFF0000,0xFFFF0000,0xFFFF0000,0xFFFF0000,0xFFFF0000 }, + { 0x00000000,0xFFFFFFFF,0x00000000,0xFFFFFFFF,0x00000000,0xFFFFFFFF,0x00000000,0xFFFFFFFF }, + { 0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF,0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF }, + { 0x00000000,0x00000000,0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF } + }; + static char Cases[256] = { + 0, // 00000000 + 0, // 00000001 + 1, // 00000010 + 0, // 00000011 + 2, // 00000100 + -1, // 00000101 + -1, // 00000110 + 0, // 00000111 + 3, // 00001000 + -1, // 00001001 + -1, // 00001010 + -1, // 00001011 + -1, // 00001100 + -1, // 00001101 + -1, // 00001110 + 0, // 00001111 + 4, // 00010000 + -1, // 00010001 + -1, // 00010010 + -1, // 00010011 + -1, // 00010100 + -1, // 00010101 + -1, // 00010110 + -1, // 00010111 + -1, // 00011000 + -1, // 00011001 + -1, // 00011010 + -1, // 00011011 + -1, // 00011100 + -1, // 00011101 + -1, // 00011110 + 0, // 00011111 + 5, // 00100000 + -1, // 00100001 + -1, // 00100010 + -1, // 00100011 + -1, // 00100100 + -1, // 00100101 + -1, // 00100110 + -1, // 00100111 + -1, // 00101000 + -1, // 00101001 + -1, // 00101010 + -1, // 00101011 + -1, // 00101100 + -1, // 00101101 + -1, // 00101110 + -1, // 00101111 + -1, // 00110000 + -1, // 00110001 + -1, // 00110010 + -1, // 00110011 + -1, // 00110100 + -1, // 00110101 + -1, // 00110110 + -1, // 00110111 + -1, // 00111000 + -1, // 00111001 + -1, // 00111010 + -1, // 00111011 + -1, // 00111100 + -1, // 00111101 + -1, // 00111110 + 0, // 00111111 + 6, // 01000000 + -1, // 01000001 + -1, // 01000010 + -1, // 01000011 + -1, // 01000100 + -1, // 01000101 + -1, // 01000110 + -1, // 01000111 + -1, // 01001000 + -1, // 01001001 + -1, // 01001010 + -1, // 01001011 + -1, // 01001100 + -1, // 01001101 + -1, // 01001110 + -1, // 01001111 + -1, // 01010000 + -1, // 01010001 + -1, // 01010010 + -1, // 01010011 + -1, // 01010100 + -1, // 01010101 + -1, // 01010110 + -1, // 01010111 + -1, // 01011000 + -1, // 01011001 + -1, // 01011010 + -1, // 01011011 + -1, // 01011100 + -1, // 01011101 + -1, // 01011110 + -1, // 01011111 + -1, // 01100000 + -1, // 01100001 + -1, // 01100010 + -1, // 01100011 + -1, // 01100100 + -1, // 01100101 + -1, // 01100110 + -1, // 01100111 + -1, // 01101000 + -1, // 01101001 + -1, // 01101010 + -1, // 01101011 + -1, // 01101100 + -1, // 01101101 + -1, // 01101110 + -1, // 01101111 + -1, // 01110000 + -1, // 01110001 + -1, // 01110010 + -1, // 01110011 + -1, // 01110100 + -1, // 01110101 + -1, // 01110110 + -1, // 01110111 + -1, // 01111000 + -1, // 01111001 + -1, // 01111010 + -1, // 01111011 + -1, // 01111100 + -1, // 01111101 + -1, // 01111110 + 0, // 01111111 + 7, // 10000000 + -1, // 10000001 + -1, // 10000010 + -1, // 10000011 + -1, // 10000100 + -1, // 10000101 + -1, // 10000110 + -1, // 10000111 + -1, // 10001000 + -1, // 10001001 + -1, // 10001010 + -1, // 10001011 + -1, // 10001100 + -1, // 10001101 + -1, // 10001110 + -1, // 10001111 + -1, // 10010000 + -1, // 10010001 + -1, // 10010010 + -1, // 10010011 + -1, // 10010100 + -1, // 10010101 + -1, // 10010110 + -1, // 10010111 + -1, // 10011000 + -1, // 10011001 + -1, // 10011010 + -1, // 10011011 + -1, // 10011100 + -1, // 10011101 + -1, // 10011110 + -1, // 10011111 + -1, // 10100000 + -1, // 10100001 + -1, // 10100010 + -1, // 10100011 + -1, // 10100100 + -1, // 10100101 + -1, // 10100110 + -1, // 10100111 + -1, // 10101000 + -1, // 10101001 + -1, // 10101010 + -1, // 10101011 + -1, // 10101100 + -1, // 10101101 + -1, // 10101110 + -1, // 10101111 + -1, // 10110000 + -1, // 10110001 + -1, // 10110010 + -1, // 10110011 + -1, // 10110100 + -1, // 10110101 + -1, // 10110110 + -1, // 10110111 + -1, // 10111000 + -1, // 10111001 + -1, // 10111010 + -1, // 10111011 + -1, // 10111100 + -1, // 10111101 + -1, // 10111110 + -1, // 10111111 + -1, // 11000000 + -1, // 11000001 + -1, // 11000010 + -1, // 11000011 + -1, // 11000100 + -1, // 11000101 + -1, // 11000110 + -1, // 11000111 + -1, // 11001000 + -1, // 11001001 + -1, // 11001010 + -1, // 11001011 + -1, // 11001100 + -1, // 11001101 + -1, // 11001110 + -1, // 11001111 + -1, // 11010000 + -1, // 11010001 + -1, // 11010010 + -1, // 11010011 + -1, // 11010100 + -1, // 11010101 + -1, // 11010110 + -1, // 11010111 + -1, // 11011000 + -1, // 11011001 + -1, // 11011010 + -1, // 11011011 + -1, // 11011100 + -1, // 11011101 + -1, // 11011110 + -1, // 11011111 + -1, // 11100000 + -1, // 11100001 + -1, // 11100010 + -1, // 11100011 + -1, // 11100100 + -1, // 11100101 + -1, // 11100110 + -1, // 11100111 + -1, // 11101000 + -1, // 11101001 + -1, // 11101010 + -1, // 11101011 + -1, // 11101100 + -1, // 11101101 + -1, // 11101110 + -1, // 11101111 + -1, // 11110000 + -1, // 11110001 + -1, // 11110010 + -1, // 11110011 + -1, // 11110100 + -1, // 11110101 + -1, // 11110110 + -1, // 11110111 + -1, // 11111000 + -1, // 11111001 + -1, // 11111010 + -1, // 11111011 + -1, // 11111100 + -1, // 11111101 + -1, // 11111110 + 0 // 11111111 + }; + static char Perms[256][8] = { + { 0, 1, 2, 3, 4, 5, 6, 7 }, // 00000000 + { 0, 1, 2, 3, 4, 5, 6, 7 }, // 00000001 + { 1, 0, 2, 3, 4, 5, 6, 7 }, // 00000010 + { 0, 1, 2, 3, 4, 5, 6, 7 }, // 00000011 + { 1, 2, 0, 3, 4, 5, 6, 7 }, // 00000100 + { 0, 2, 1, 3, 4, 5, 6, 7 }, // 00000101 + { 2, 0, 1, 3, 4, 5, 6, 7 }, // 00000110 + { 0, 1, 2, 3, 4, 5, 6, 7 }, // 00000111 + { 1, 2, 3, 0, 4, 5, 6, 7 }, // 00001000 + { 0, 2, 3, 1, 4, 5, 6, 7 }, // 00001001 + { 2, 0, 3, 1, 4, 5, 6, 7 }, // 00001010 + { 0, 1, 3, 2, 4, 5, 6, 7 }, // 00001011 + { 2, 3, 0, 1, 4, 5, 6, 7 }, // 00001100 + { 0, 3, 1, 2, 4, 5, 6, 7 }, // 00001101 + { 3, 0, 1, 2, 4, 5, 6, 7 }, // 00001110 + { 0, 1, 2, 3, 4, 5, 6, 7 }, // 00001111 + { 1, 2, 3, 4, 0, 5, 6, 7 }, // 00010000 + { 0, 2, 3, 4, 1, 5, 6, 7 }, // 00010001 + { 2, 0, 3, 4, 1, 5, 6, 7 }, // 00010010 + { 0, 1, 3, 4, 2, 5, 6, 7 }, // 00010011 + { 2, 3, 0, 4, 1, 5, 6, 7 }, // 00010100 + { 0, 3, 1, 4, 2, 5, 6, 7 }, // 00010101 + { 3, 0, 1, 4, 2, 5, 6, 7 }, // 00010110 + { 0, 1, 2, 4, 3, 5, 6, 7 }, // 00010111 + { 2, 3, 4, 0, 1, 5, 6, 7 }, // 00011000 + { 0, 3, 4, 1, 2, 5, 6, 7 }, // 00011001 + { 3, 0, 4, 1, 2, 5, 6, 7 }, // 00011010 + { 0, 1, 4, 2, 3, 5, 6, 7 }, // 00011011 + { 3, 4, 0, 1, 2, 5, 6, 7 }, // 00011100 + { 0, 4, 1, 2, 3, 5, 6, 7 }, // 00011101 + { 4, 0, 1, 2, 3, 5, 6, 7 }, // 00011110 + { 0, 1, 2, 3, 4, 5, 6, 7 }, // 00011111 + { 1, 2, 3, 4, 5, 0, 6, 7 }, // 00100000 + { 0, 2, 3, 4, 5, 1, 6, 7 }, // 00100001 + { 2, 0, 3, 4, 5, 1, 6, 7 }, // 00100010 + { 0, 1, 3, 4, 5, 2, 6, 7 }, // 00100011 + { 2, 3, 0, 4, 5, 1, 6, 7 }, // 00100100 + { 0, 3, 1, 4, 5, 2, 6, 7 }, // 00100101 + { 3, 0, 1, 4, 5, 2, 6, 7 }, // 00100110 + { 0, 1, 2, 4, 5, 3, 6, 7 }, // 00100111 + { 2, 3, 4, 0, 5, 1, 6, 7 }, // 00101000 + { 0, 3, 4, 1, 5, 2, 6, 7 }, // 00101001 + { 3, 0, 4, 1, 5, 2, 6, 7 }, // 00101010 + { 0, 1, 4, 2, 5, 3, 6, 7 }, // 00101011 + { 3, 4, 0, 1, 5, 2, 6, 7 }, // 00101100 + { 0, 4, 1, 2, 5, 3, 6, 7 }, // 00101101 + { 4, 0, 1, 2, 5, 3, 6, 7 }, // 00101110 + { 0, 1, 2, 3, 5, 4, 6, 7 }, // 00101111 + { 2, 3, 4, 5, 0, 1, 6, 7 }, // 00110000 + { 0, 3, 4, 5, 1, 2, 6, 7 }, // 00110001 + { 3, 0, 4, 5, 1, 2, 6, 7 }, // 00110010 + { 0, 1, 4, 5, 2, 3, 6, 7 }, // 00110011 + { 3, 4, 0, 5, 1, 2, 6, 7 }, // 00110100 + { 0, 4, 1, 5, 2, 3, 6, 7 }, // 00110101 + { 4, 0, 1, 5, 2, 3, 6, 7 }, // 00110110 + { 0, 1, 2, 5, 3, 4, 6, 7 }, // 00110111 + { 3, 4, 5, 0, 1, 2, 6, 7 }, // 00111000 + { 0, 4, 5, 1, 2, 3, 6, 7 }, // 00111001 + { 4, 0, 5, 1, 2, 3, 6, 7 }, // 00111010 + { 0, 1, 5, 2, 3, 4, 6, 7 }, // 00111011 + { 4, 5, 0, 1, 2, 3, 6, 7 }, // 00111100 + { 0, 5, 1, 2, 3, 4, 6, 7 }, // 00111101 + { 5, 0, 1, 2, 3, 4, 6, 7 }, // 00111110 + { 0, 1, 2, 3, 4, 5, 6, 7 }, // 00111111 + { 1, 2, 3, 4, 5, 6, 0, 7 }, // 01000000 + { 0, 2, 3, 4, 5, 6, 1, 7 }, // 01000001 + { 2, 0, 3, 4, 5, 6, 1, 7 }, // 01000010 + { 0, 1, 3, 4, 5, 6, 2, 7 }, // 01000011 + { 2, 3, 0, 4, 5, 6, 1, 7 }, // 01000100 + { 0, 3, 1, 4, 5, 6, 2, 7 }, // 01000101 + { 3, 0, 1, 4, 5, 6, 2, 7 }, // 01000110 + { 0, 1, 2, 4, 5, 6, 3, 7 }, // 01000111 + { 2, 3, 4, 0, 5, 6, 1, 7 }, // 01001000 + { 0, 3, 4, 1, 5, 6, 2, 7 }, // 01001001 + { 3, 0, 4, 1, 5, 6, 2, 7 }, // 01001010 + { 0, 1, 4, 2, 5, 6, 3, 7 }, // 01001011 + { 3, 4, 0, 1, 5, 6, 2, 7 }, // 01001100 + { 0, 4, 1, 2, 5, 6, 3, 7 }, // 01001101 + { 4, 0, 1, 2, 5, 6, 3, 7 }, // 01001110 + { 0, 1, 2, 3, 5, 6, 4, 7 }, // 01001111 + { 2, 3, 4, 5, 0, 6, 1, 7 }, // 01010000 + { 0, 3, 4, 5, 1, 6, 2, 7 }, // 01010001 + { 3, 0, 4, 5, 1, 6, 2, 7 }, // 01010010 + { 0, 1, 4, 5, 2, 6, 3, 7 }, // 01010011 + { 3, 4, 0, 5, 1, 6, 2, 7 }, // 01010100 + { 0, 4, 1, 5, 2, 6, 3, 7 }, // 01010101 + { 4, 0, 1, 5, 2, 6, 3, 7 }, // 01010110 + { 0, 1, 2, 5, 3, 6, 4, 7 }, // 01010111 + { 3, 4, 5, 0, 1, 6, 2, 7 }, // 01011000 + { 0, 4, 5, 1, 2, 6, 3, 7 }, // 01011001 + { 4, 0, 5, 1, 2, 6, 3, 7 }, // 01011010 + { 0, 1, 5, 2, 3, 6, 4, 7 }, // 01011011 + { 4, 5, 0, 1, 2, 6, 3, 7 }, // 01011100 + { 0, 5, 1, 2, 3, 6, 4, 7 }, // 01011101 + { 5, 0, 1, 2, 3, 6, 4, 7 }, // 01011110 + { 0, 1, 2, 3, 4, 6, 5, 7 }, // 01011111 + { 2, 3, 4, 5, 6, 0, 1, 7 }, // 01100000 + { 0, 3, 4, 5, 6, 1, 2, 7 }, // 01100001 + { 3, 0, 4, 5, 6, 1, 2, 7 }, // 01100010 + { 0, 1, 4, 5, 6, 2, 3, 7 }, // 01100011 + { 3, 4, 0, 5, 6, 1, 2, 7 }, // 01100100 + { 0, 4, 1, 5, 6, 2, 3, 7 }, // 01100101 + { 4, 0, 1, 5, 6, 2, 3, 7 }, // 01100110 + { 0, 1, 2, 5, 6, 3, 4, 7 }, // 01100111 + { 3, 4, 5, 0, 6, 1, 2, 7 }, // 01101000 + { 0, 4, 5, 1, 6, 2, 3, 7 }, // 01101001 + { 4, 0, 5, 1, 6, 2, 3, 7 }, // 01101010 + { 0, 1, 5, 2, 6, 3, 4, 7 }, // 01101011 + { 4, 5, 0, 1, 6, 2, 3, 7 }, // 01101100 + { 0, 5, 1, 2, 6, 3, 4, 7 }, // 01101101 + { 5, 0, 1, 2, 6, 3, 4, 7 }, // 01101110 + { 0, 1, 2, 3, 6, 4, 5, 7 }, // 01101111 + { 3, 4, 5, 6, 0, 1, 2, 7 }, // 01110000 + { 0, 4, 5, 6, 1, 2, 3, 7 }, // 01110001 + { 4, 0, 5, 6, 1, 2, 3, 7 }, // 01110010 + { 0, 1, 5, 6, 2, 3, 4, 7 }, // 01110011 + { 4, 5, 0, 6, 1, 2, 3, 7 }, // 01110100 + { 0, 5, 1, 6, 2, 3, 4, 7 }, // 01110101 + { 5, 0, 1, 6, 2, 3, 4, 7 }, // 01110110 + { 0, 1, 2, 6, 3, 4, 5, 7 }, // 01110111 + { 4, 5, 6, 0, 1, 2, 3, 7 }, // 01111000 + { 0, 5, 6, 1, 2, 3, 4, 7 }, // 01111001 + { 5, 0, 6, 1, 2, 3, 4, 7 }, // 01111010 + { 0, 1, 6, 2, 3, 4, 5, 7 }, // 01111011 + { 5, 6, 0, 1, 2, 3, 4, 7 }, // 01111100 + { 0, 6, 1, 2, 3, 4, 5, 7 }, // 01111101 + { 6, 0, 1, 2, 3, 4, 5, 7 }, // 01111110 + { 0, 1, 2, 3, 4, 5, 6, 7 }, // 01111111 + { 1, 2, 3, 4, 5, 6, 7, 0 }, // 10000000 + { 0, 2, 3, 4, 5, 6, 7, 1 }, // 10000001 + { 2, 0, 3, 4, 5, 6, 7, 1 }, // 10000010 + { 0, 1, 3, 4, 5, 6, 7, 2 }, // 10000011 + { 2, 3, 0, 4, 5, 6, 7, 1 }, // 10000100 + { 0, 3, 1, 4, 5, 6, 7, 2 }, // 10000101 + { 3, 0, 1, 4, 5, 6, 7, 2 }, // 10000110 + { 0, 1, 2, 4, 5, 6, 7, 3 }, // 10000111 + { 2, 3, 4, 0, 5, 6, 7, 1 }, // 10001000 + { 0, 3, 4, 1, 5, 6, 7, 2 }, // 10001001 + { 3, 0, 4, 1, 5, 6, 7, 2 }, // 10001010 + { 0, 1, 4, 2, 5, 6, 7, 3 }, // 10001011 + { 3, 4, 0, 1, 5, 6, 7, 2 }, // 10001100 + { 0, 4, 1, 2, 5, 6, 7, 3 }, // 10001101 + { 4, 0, 1, 2, 5, 6, 7, 3 }, // 10001110 + { 0, 1, 2, 3, 5, 6, 7, 4 }, // 10001111 + { 2, 3, 4, 5, 0, 6, 7, 1 }, // 10010000 + { 0, 3, 4, 5, 1, 6, 7, 2 }, // 10010001 + { 3, 0, 4, 5, 1, 6, 7, 2 }, // 10010010 + { 0, 1, 4, 5, 2, 6, 7, 3 }, // 10010011 + { 3, 4, 0, 5, 1, 6, 7, 2 }, // 10010100 + { 0, 4, 1, 5, 2, 6, 7, 3 }, // 10010101 + { 4, 0, 1, 5, 2, 6, 7, 3 }, // 10010110 + { 0, 1, 2, 5, 3, 6, 7, 4 }, // 10010111 + { 3, 4, 5, 0, 1, 6, 7, 2 }, // 10011000 + { 0, 4, 5, 1, 2, 6, 7, 3 }, // 10011001 + { 4, 0, 5, 1, 2, 6, 7, 3 }, // 10011010 + { 0, 1, 5, 2, 3, 6, 7, 4 }, // 10011011 + { 4, 5, 0, 1, 2, 6, 7, 3 }, // 10011100 + { 0, 5, 1, 2, 3, 6, 7, 4 }, // 10011101 + { 5, 0, 1, 2, 3, 6, 7, 4 }, // 10011110 + { 0, 1, 2, 3, 4, 6, 7, 5 }, // 10011111 + { 2, 3, 4, 5, 6, 0, 7, 1 }, // 10100000 + { 0, 3, 4, 5, 6, 1, 7, 2 }, // 10100001 + { 3, 0, 4, 5, 6, 1, 7, 2 }, // 10100010 + { 0, 1, 4, 5, 6, 2, 7, 3 }, // 10100011 + { 3, 4, 0, 5, 6, 1, 7, 2 }, // 10100100 + { 0, 4, 1, 5, 6, 2, 7, 3 }, // 10100101 + { 4, 0, 1, 5, 6, 2, 7, 3 }, // 10100110 + { 0, 1, 2, 5, 6, 3, 7, 4 }, // 10100111 + { 3, 4, 5, 0, 6, 1, 7, 2 }, // 10101000 + { 0, 4, 5, 1, 6, 2, 7, 3 }, // 10101001 + { 4, 0, 5, 1, 6, 2, 7, 3 }, // 10101010 + { 0, 1, 5, 2, 6, 3, 7, 4 }, // 10101011 + { 4, 5, 0, 1, 6, 2, 7, 3 }, // 10101100 + { 0, 5, 1, 2, 6, 3, 7, 4 }, // 10101101 + { 5, 0, 1, 2, 6, 3, 7, 4 }, // 10101110 + { 0, 1, 2, 3, 6, 4, 7, 5 }, // 10101111 + { 3, 4, 5, 6, 0, 1, 7, 2 }, // 10110000 + { 0, 4, 5, 6, 1, 2, 7, 3 }, // 10110001 + { 4, 0, 5, 6, 1, 2, 7, 3 }, // 10110010 + { 0, 1, 5, 6, 2, 3, 7, 4 }, // 10110011 + { 4, 5, 0, 6, 1, 2, 7, 3 }, // 10110100 + { 0, 5, 1, 6, 2, 3, 7, 4 }, // 10110101 + { 5, 0, 1, 6, 2, 3, 7, 4 }, // 10110110 + { 0, 1, 2, 6, 3, 4, 7, 5 }, // 10110111 + { 4, 5, 6, 0, 1, 2, 7, 3 }, // 10111000 + { 0, 5, 6, 1, 2, 3, 7, 4 }, // 10111001 + { 5, 0, 6, 1, 2, 3, 7, 4 }, // 10111010 + { 0, 1, 6, 2, 3, 4, 7, 5 }, // 10111011 + { 5, 6, 0, 1, 2, 3, 7, 4 }, // 10111100 + { 0, 6, 1, 2, 3, 4, 7, 5 }, // 10111101 + { 6, 0, 1, 2, 3, 4, 7, 5 }, // 10111110 + { 0, 1, 2, 3, 4, 5, 7, 6 }, // 10111111 + { 2, 3, 4, 5, 6, 7, 0, 1 }, // 11000000 + { 0, 3, 4, 5, 6, 7, 1, 2 }, // 11000001 + { 3, 0, 4, 5, 6, 7, 1, 2 }, // 11000010 + { 0, 1, 4, 5, 6, 7, 2, 3 }, // 11000011 + { 3, 4, 0, 5, 6, 7, 1, 2 }, // 11000100 + { 0, 4, 1, 5, 6, 7, 2, 3 }, // 11000101 + { 4, 0, 1, 5, 6, 7, 2, 3 }, // 11000110 + { 0, 1, 2, 5, 6, 7, 3, 4 }, // 11000111 + { 3, 4, 5, 0, 6, 7, 1, 2 }, // 11001000 + { 0, 4, 5, 1, 6, 7, 2, 3 }, // 11001001 + { 4, 0, 5, 1, 6, 7, 2, 3 }, // 11001010 + { 0, 1, 5, 2, 6, 7, 3, 4 }, // 11001011 + { 4, 5, 0, 1, 6, 7, 2, 3 }, // 11001100 + { 0, 5, 1, 2, 6, 7, 3, 4 }, // 11001101 + { 5, 0, 1, 2, 6, 7, 3, 4 }, // 11001110 + { 0, 1, 2, 3, 6, 7, 4, 5 }, // 11001111 + { 3, 4, 5, 6, 0, 7, 1, 2 }, // 11010000 + { 0, 4, 5, 6, 1, 7, 2, 3 }, // 11010001 + { 4, 0, 5, 6, 1, 7, 2, 3 }, // 11010010 + { 0, 1, 5, 6, 2, 7, 3, 4 }, // 11010011 + { 4, 5, 0, 6, 1, 7, 2, 3 }, // 11010100 + { 0, 5, 1, 6, 2, 7, 3, 4 }, // 11010101 + { 5, 0, 1, 6, 2, 7, 3, 4 }, // 11010110 + { 0, 1, 2, 6, 3, 7, 4, 5 }, // 11010111 + { 4, 5, 6, 0, 1, 7, 2, 3 }, // 11011000 + { 0, 5, 6, 1, 2, 7, 3, 4 }, // 11011001 + { 5, 0, 6, 1, 2, 7, 3, 4 }, // 11011010 + { 0, 1, 6, 2, 3, 7, 4, 5 }, // 11011011 + { 5, 6, 0, 1, 2, 7, 3, 4 }, // 11011100 + { 0, 6, 1, 2, 3, 7, 4, 5 }, // 11011101 + { 6, 0, 1, 2, 3, 7, 4, 5 }, // 11011110 + { 0, 1, 2, 3, 4, 7, 5, 6 }, // 11011111 + { 3, 4, 5, 6, 7, 0, 1, 2 }, // 11100000 + { 0, 4, 5, 6, 7, 1, 2, 3 }, // 11100001 + { 4, 0, 5, 6, 7, 1, 2, 3 }, // 11100010 + { 0, 1, 5, 6, 7, 2, 3, 4 }, // 11100011 + { 4, 5, 0, 6, 7, 1, 2, 3 }, // 11100100 + { 0, 5, 1, 6, 7, 2, 3, 4 }, // 11100101 + { 5, 0, 1, 6, 7, 2, 3, 4 }, // 11100110 + { 0, 1, 2, 6, 7, 3, 4, 5 }, // 11100111 + { 4, 5, 6, 0, 7, 1, 2, 3 }, // 11101000 + { 0, 5, 6, 1, 7, 2, 3, 4 }, // 11101001 + { 5, 0, 6, 1, 7, 2, 3, 4 }, // 11101010 + { 0, 1, 6, 2, 7, 3, 4, 5 }, // 11101011 + { 5, 6, 0, 1, 7, 2, 3, 4 }, // 11101100 + { 0, 6, 1, 2, 7, 3, 4, 5 }, // 11101101 + { 6, 0, 1, 2, 7, 3, 4, 5 }, // 11101110 + { 0, 1, 2, 3, 7, 4, 5, 6 }, // 11101111 + { 4, 5, 6, 7, 0, 1, 2, 3 }, // 11110000 + { 0, 5, 6, 7, 1, 2, 3, 4 }, // 11110001 + { 5, 0, 6, 7, 1, 2, 3, 4 }, // 11110010 + { 0, 1, 6, 7, 2, 3, 4, 5 }, // 11110011 + { 5, 6, 0, 7, 1, 2, 3, 4 }, // 11110100 + { 0, 6, 1, 7, 2, 3, 4, 5 }, // 11110101 + { 6, 0, 1, 7, 2, 3, 4, 5 }, // 11110110 + { 0, 1, 2, 7, 3, 4, 5, 6 }, // 11110111 + { 5, 6, 7, 0, 1, 2, 3, 4 }, // 11111000 + { 0, 6, 7, 1, 2, 3, 4, 5 }, // 11111001 + { 6, 0, 7, 1, 2, 3, 4, 5 }, // 11111010 + { 0, 1, 7, 2, 3, 4, 5, 6 }, // 11111011 + { 6, 7, 0, 1, 2, 3, 4, 5 }, // 11111100 + { 0, 7, 1, 2, 3, 4, 5, 6 }, // 11111101 + { 7, 0, 1, 2, 3, 4, 5, 6 }, // 11111110 + { 0, 1, 2, 3, 4, 5, 6, 7 } // 11111111 + }; + + assert( uPhase > 0 && uPhase < (unsigned)(1 << nVars) ); + + // the same function + if ( Cases[uPhase] == 0 ) + { + int i; + for ( i = 0; i < nWords; i++ ) + puTruthR[i] = puTruth[i]; + return; + } + + // an elementary variable + if ( Cases[uPhase] > 0 ) + { + int i; + for ( i = 0; i < nWords; i++ ) + puTruthR[i] = uTruths[Cases[uPhase]][i]; + return; + } + + // truth table takes one word + if ( nWords == 1 ) + { + int i, k, nMints, iRes; + char * pPerm = Perms[uPhase]; + puTruthR[0] = 0; + nMints = (1 << nVars); + for ( i = 0; i < nMints; i++ ) + if ( puTruth[0] & (1 << i) ) + { + for ( iRes = 0, k = 0; k < nVars; k++ ) + if ( i & (1 << pPerm[k]) ) + iRes |= (1 << k); + puTruthR[0] |= (1 << iRes); + } + return; + } + else if ( nWords == 2 ) + { + int i, k, iRes; + char * pPerm = Perms[uPhase]; + puTruthR[0] = puTruthR[1] = 0; + for ( i = 0; i < 32; i++ ) + { + if ( puTruth[0] & (1 << i) ) + { + for ( iRes = 0, k = 0; k < 6; k++ ) + if ( i & (1 << pPerm[k]) ) + iRes |= (1 << k); + if ( iRes < 32 ) + puTruthR[0] |= (1 << iRes); + else + puTruthR[1] |= (1 << (iRes-32)); + } + } + for ( ; i < 64; i++ ) + { + if ( puTruth[1] & (1 << (i-32)) ) + { + for ( iRes = 0, k = 0; k < 6; k++ ) + if ( i & (1 << pPerm[k]) ) + iRes |= (1 << k); + if ( iRes < 32 ) + puTruthR[0] |= (1 << iRes); + else + puTruthR[1] |= (1 << (iRes-32)); + } + } + } + // truth table takes more than one word + else + { + int i, k, nMints, iRes; + char * pPerm = Perms[uPhase]; + for ( i = 0; i < nWords; i++ ) + puTruthR[i] = 0; + nMints = (1 << nVars); + for ( i = 0; i < nMints; i++ ) + if ( puTruth[i>>5] & (1 << (i&31)) ) + { + for ( iRes = 0, k = 0; k < 5; k++ ) + if ( i & (1 << pPerm[k]) ) + iRes |= (1 << k); + puTruthR[iRes>>5] |= (1 << (iRes&31)); + } + } +} + +/**Function************************************************************* + + Synopsis [Allocated lookup table for truth table permutation.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +unsigned short ** Extra_TruthPerm43() +{ + unsigned short ** pTable; + unsigned uTruth; + int i, k; + pTable = (unsigned short **)Extra_ArrayAlloc( 256, 16, 2 ); + for ( i = 0; i < 256; i++ ) + { + uTruth = (i << 8) | i; + for ( k = 0; k < 16; k++ ) + pTable[i][k] = Extra_TruthPerm4One( uTruth, k ); + } + return pTable; +} + +/**Function************************************************************* + + Synopsis [Allocated lookup table for truth table permutation.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +unsigned ** Extra_TruthPerm53() +{ + unsigned ** pTable; + unsigned uTruth; + int i, k; + pTable = (unsigned **)Extra_ArrayAlloc( 256, 32, 4 ); + for ( i = 0; i < 256; i++ ) + { + uTruth = (i << 24) | (i << 16) | (i << 8) | i; + for ( k = 0; k < 32; k++ ) + pTable[i][k] = Extra_TruthPerm5One( uTruth, k ); + } + return pTable; +} + +/**Function************************************************************* + + Synopsis [Allocated lookup table for truth table permutation.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +unsigned ** Extra_TruthPerm54() +{ + unsigned ** pTable; + unsigned uTruth; + int i; + pTable = (unsigned **)Extra_ArrayAlloc( 256*256, 4, 4 ); + for ( i = 0; i < 256*256; i++ ) + { + uTruth = (i << 16) | i; + pTable[i][0] = Extra_TruthPerm5One( uTruth, 31-8 ); + pTable[i][1] = Extra_TruthPerm5One( uTruth, 31-4 ); + pTable[i][2] = Extra_TruthPerm5One( uTruth, 31-2 ); + pTable[i][3] = Extra_TruthPerm5One( uTruth, 31-1 ); + } + return pTable; +} + +/**Function************************************************************* + + Synopsis [Allocated lookup table for truth table permutation.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +unsigned ** Extra_TruthPerm63() +{ + unsigned ** pTable; + unsigned uTruth[2]; + int i, k; + pTable = (unsigned **)Extra_ArrayAlloc( 256, 64, 8 ); + for ( i = 0; i < 256; i++ ) + { + uTruth[0] = (i << 24) | (i << 16) | (i << 8) | i; + uTruth[1] = uTruth[0]; + for ( k = 0; k < 64; k++ ) + Extra_TruthPerm6One( uTruth, k, &pTable[i][k] ); + } + return pTable; +} + +/**Function************************************************************* + + Synopsis [Returns the pointer to the elementary truth tables.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +unsigned ** Extra_Truths8() +{ + static unsigned uTruths[8][8] = { + { 0xAAAAAAAA,0xAAAAAAAA,0xAAAAAAAA,0xAAAAAAAA,0xAAAAAAAA,0xAAAAAAAA,0xAAAAAAAA,0xAAAAAAAA }, + { 0xCCCCCCCC,0xCCCCCCCC,0xCCCCCCCC,0xCCCCCCCC,0xCCCCCCCC,0xCCCCCCCC,0xCCCCCCCC,0xCCCCCCCC }, + { 0xF0F0F0F0,0xF0F0F0F0,0xF0F0F0F0,0xF0F0F0F0,0xF0F0F0F0,0xF0F0F0F0,0xF0F0F0F0,0xF0F0F0F0 }, + { 0xFF00FF00,0xFF00FF00,0xFF00FF00,0xFF00FF00,0xFF00FF00,0xFF00FF00,0xFF00FF00,0xFF00FF00 }, + { 0xFFFF0000,0xFFFF0000,0xFFFF0000,0xFFFF0000,0xFFFF0000,0xFFFF0000,0xFFFF0000,0xFFFF0000 }, + { 0x00000000,0xFFFFFFFF,0x00000000,0xFFFFFFFF,0x00000000,0xFFFFFFFF,0x00000000,0xFFFFFFFF }, + { 0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF,0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF }, + { 0x00000000,0x00000000,0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF } + }; + static unsigned * puResult[8] = { + uTruths[0], uTruths[1], uTruths[2], uTruths[3], uTruths[4], uTruths[5], uTruths[6], uTruths[7] + }; + return (unsigned **)puResult; +} + +/**Function************************************************************* + + Synopsis [Bubble-sorts components by scores in increasing order.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_BubbleSort( int Order[], int Costs[], int nSize, int fIncreasing ) +{ + int i, Temp, fChanges; + assert( nSize < 1000 ); + for ( i = 0; i < nSize; i++ ) + Order[i] = i; + if ( fIncreasing ) + { + do { + fChanges = 0; + for ( i = 0; i < nSize - 1; i++ ) + { + if ( Costs[Order[i]] <= Costs[Order[i+1]] ) + continue; + Temp = Order[i]; + Order[i] = Order[i+1]; + Order[i+1] = Temp; + fChanges = 1; + } + } while ( fChanges ); + } + else + { + do { + fChanges = 0; + for ( i = 0; i < nSize - 1; i++ ) + { + if ( Costs[Order[i]] >= Costs[Order[i+1]] ) + continue; + Temp = Order[i]; + Order[i] = Order[i+1]; + Order[i+1] = Temp; + fChanges = 1; + } + } while ( fChanges ); + } +} + +/**Function************************************************************* + + Synopsis [Returns the smallest prime larger than the number.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +unsigned int Cudd_PrimeCopy( unsigned int p) +{ + int i,pn; + + p--; + do { + p++; + if (p&1) { + pn = 1; + i = 3; + while ((unsigned) (i * i) <= p) { + if (p % i == 0) { + pn = 0; + break; + } + i += 2; + } + } else { + pn = 0; + } + } while (!pn); + return(p); + +} /* end of Cudd_Prime */ + +/*---------------------------------------------------------------------------*/ +/* Definition of internal functions */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Definition of static Functions */ +/*---------------------------------------------------------------------------*/ + + +/**Function************************************************************* + + Synopsis [Computes the permutation table for 8 variables.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_TruthExpandGeneratePermTable() +{ + int i, k, nOnes, Last1, First0; + int iOne, iZero; + + printf( "\nstatic char Cases[256] = {\n" ); + for ( i = 0; i < 256; i++ ) + { + nOnes = 0; + Last1 = First0 = -1; + for ( k = 0; k < 8; k++ ) + { + if ( i & (1 << k) ) + { + nOnes++; + Last1 = k; + } + else if ( First0 == -1 ) + First0 = k; + } + if ( Last1 + 1 == First0 || i == 255 ) + printf( " %d%s", 0, (i==255? " ":",") ); + else if ( nOnes == 1 ) + printf( " %d,", Last1 ); + else + printf( " -%d,", 1 ); + printf( " // " ); + Extra_PrintBinary( stdout, (unsigned*)&i, 8 ); + printf( "\n" ); + } + printf( "};\n" ); + + printf( "\nstatic char Perms[256][8] = {\n" ); + for ( i = 0; i < 256; i++ ) + { + printf( " {" ); + nOnes = 0; + for ( k = 0; k < 8; k++ ) + if ( i & (1 << k) ) + nOnes++; + iOne = 0; + iZero = nOnes; + for ( k = 0; k < 8; k++ ) + if ( i & (1 << k) ) + printf( "%s %d", (k==0? "":","), iOne++ ); + else + printf( "%s %d", (k==0? "":","), iZero++ ); + assert( iOne + iZero == 8 ); + printf( " }%s // ", (i==255? " ":",") ); + Extra_PrintBinary( stdout, (unsigned*)&i, 8 ); + printf( "\n" ); + } + printf( "};\n" ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/misc/extra/extraUtilProgress.c b/src/misc/extra/extraUtilProgress.c new file mode 100644 index 00000000..6b6d5132 --- /dev/null +++ b/src/misc/extra/extraUtilProgress.c @@ -0,0 +1,176 @@ +/**CFile**************************************************************** + + FileName [extraUtilProgress.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [extra] + + Synopsis [Progress bar.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: extraUtilProgress.c,v 1.0 2003/02/01 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include +#include "extra.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +struct ProgressBarStruct +{ + int nItemsNext; // the number of items for the next update of the progress bar + int nItemsTotal; // the total number of items + int posTotal; // the total number of positions + int posCur; // the current position + FILE * pFile; // the output stream +}; + +static void Extra_ProgressBarShow( ProgressBar * p, char * pString ); +static void Extra_ProgressBarClean( ProgressBar * p ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Starts the progress bar.] + + Description [The first parameter is the output stream (pFile), where + the progress is printed. The current printing position should be the + first one on the given line. The second parameters is the total + number of items that correspond to 100% position of the progress bar.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +ProgressBar * Extra_ProgressBarStart( FILE * pFile, int nItemsTotal ) +{ + ProgressBar * p; + extern int Abc_FrameShowProgress( void * p ); + extern void * Abc_FrameGetGlobalFrame(); + + if ( !Abc_FrameShowProgress(Abc_FrameGetGlobalFrame()) ) return NULL; + p = ALLOC( ProgressBar, 1 ); + memset( p, 0, sizeof(ProgressBar) ); + p->pFile = pFile; + p->nItemsTotal = nItemsTotal; + p->posTotal = 78; + p->posCur = 1; + p->nItemsNext = (int)((7.0+p->posCur)*p->nItemsTotal/p->posTotal); + Extra_ProgressBarShow( p, NULL ); + return p; +} + +/**Function************************************************************* + + Synopsis [Updates the progress bar.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_ProgressBarUpdate_int( ProgressBar * p, int nItemsCur, char * pString ) +{ + if ( p == NULL ) return; + if ( nItemsCur < p->nItemsNext ) + return; + if ( nItemsCur >= p->nItemsTotal ) + { + p->posCur = 78; + p->nItemsNext = 0x7FFFFFFF; + } + else + { + p->posCur += 7; + p->nItemsNext = (int)((7.0+p->posCur)*p->nItemsTotal/p->posTotal); + } + Extra_ProgressBarShow( p, pString ); +} + + +/**Function************************************************************* + + Synopsis [Stops the progress bar.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_ProgressBarStop( ProgressBar * p ) +{ + if ( p == NULL ) return; + Extra_ProgressBarClean( p ); + FREE( p ); +} + +/**Function************************************************************* + + Synopsis [Prints the progress bar of the given size.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_ProgressBarShow( ProgressBar * p, char * pString ) +{ + int i; + if ( p == NULL ) return; + if ( pString ) + fprintf( p->pFile, "%s ", pString ); + for ( i = (pString? strlen(pString) + 1 : 0); i < p->posCur; i++ ) + fprintf( p->pFile, "-" ); + if ( i == p->posCur ) + fprintf( p->pFile, ">" ); + for ( i++ ; i <= p->posTotal; i++ ) + fprintf( p->pFile, " " ); + fprintf( p->pFile, "\r" ); + fflush( stdout ); +} + +/**Function************************************************************* + + Synopsis [Cleans the progress bar before quitting.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_ProgressBarClean( ProgressBar * p ) +{ + int i; + if ( p == NULL ) return; + for ( i = 0; i <= p->posTotal; i++ ) + fprintf( p->pFile, " " ); + fprintf( p->pFile, "\r" ); + fflush( stdout ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/misc/extra/extraUtilReader.c b/src/misc/extra/extraUtilReader.c new file mode 100644 index 00000000..c165b989 --- /dev/null +++ b/src/misc/extra/extraUtilReader.c @@ -0,0 +1,383 @@ +/**CFile**************************************************************** + + FileName [extraUtilReader.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [extra] + + Synopsis [File reading utilities.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: extraUtilReader.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include +#include "extra.h" +#include "vec.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +#define EXTRA_BUFFER_SIZE 4*1048576 // 1M - size of the data chunk stored in memory +#define EXTRA_OFFSET_SIZE 4096 // 4K - load new data when less than this is left + +#define EXTRA_MINIMUM(a,b) (((a) < (b))? (a) : (b)) + +struct Extra_FileReader_t_ +{ + // the input file + char * pFileName; // the input file name + FILE * pFile; // the input file pointer + int nFileSize; // the total number of bytes in the file + int nFileRead; // the number of bytes currently read from file + // info about processing different types of input chars + char pCharMap[256]; // the character map + // temporary storage for data + char * pBuffer; // the buffer + int nBufferSize; // the size of the buffer + char * pBufferCur; // the current reading position + char * pBufferEnd; // the first position not used by currently loaded data + char * pBufferStop; // the position where loading new data will be done + // tokens given to the user + Vec_Ptr_t * vTokens; // the vector of tokens returned to the user + Vec_Int_t * vLines; // the vector of line numbers for each token + int nLineCounter; // the counter of lines processed + // status of the parser + int fStop; // this flag goes high when the end of file is reached +}; + +// character types +typedef enum { + EXTRA_CHAR_COMMENT, // a character that begins the comment + EXTRA_CHAR_NORMAL, // a regular character + EXTRA_CHAR_STOP, // a character that delimits a series of tokens + EXTRA_CHAR_CLEAN // a character that should be cleaned +} Extra_CharType_t; + +// the static functions +static void * Extra_FileReaderGetTokens_int( Extra_FileReader_t * p ); +static void Extra_FileReaderReload( Extra_FileReader_t * p ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Starts the file reader.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Extra_FileReader_t * Extra_FileReaderAlloc( char * pFileName, + char * pCharsComment, char * pCharsStop, char * pCharsClean ) +{ + Extra_FileReader_t * p; + FILE * pFile; + char * pChar; + int nCharsToRead; + // check if the file can be opened + pFile = fopen( pFileName, "rb" ); + if ( pFile == NULL ) + { + printf( "Extra_FileReaderAlloc(): Cannot open input file \"%s\".\n", pFileName ); + return NULL; + } + // start the file reader + p = ALLOC( Extra_FileReader_t, 1 ); + memset( p, 0, sizeof(Extra_FileReader_t) ); + p->pFileName = pFileName; + p->pFile = pFile; + // set the character map + memset( p->pCharMap, EXTRA_CHAR_NORMAL, 256 ); + for ( pChar = pCharsComment; *pChar; pChar++ ) + p->pCharMap[(unsigned char)*pChar] = EXTRA_CHAR_COMMENT; + for ( pChar = pCharsStop; *pChar; pChar++ ) + p->pCharMap[(unsigned char)*pChar] = EXTRA_CHAR_STOP; + for ( pChar = pCharsClean; *pChar; pChar++ ) + p->pCharMap[(unsigned char)*pChar] = EXTRA_CHAR_CLEAN; + // get the file size, in bytes + fseek( pFile, 0, SEEK_END ); + p->nFileSize = ftell( pFile ); + rewind( pFile ); + // allocate the buffer + p->pBuffer = ALLOC( char, EXTRA_BUFFER_SIZE+1 ); + p->nBufferSize = EXTRA_BUFFER_SIZE; + p->pBufferCur = p->pBuffer; + // determine how many chars to read + nCharsToRead = EXTRA_MINIMUM(p->nFileSize, EXTRA_BUFFER_SIZE); + // load the first part into the buffer + fread( p->pBuffer, nCharsToRead, 1, p->pFile ); + p->nFileRead = nCharsToRead; + // set the ponters to the end and the stopping point + p->pBufferEnd = p->pBuffer + nCharsToRead; + p->pBufferStop = (p->nFileRead == p->nFileSize)? p->pBufferEnd : p->pBuffer + EXTRA_BUFFER_SIZE - EXTRA_OFFSET_SIZE; + // start the arrays + p->vTokens = Vec_PtrAlloc( 100 ); + p->vLines = Vec_IntAlloc( 100 ); + p->nLineCounter = 1; // 1-based line counting + return p; +} + +/**Function************************************************************* + + Synopsis [Stops the file reader.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_FileReaderFree( Extra_FileReader_t * p ) +{ + if ( p->pFile ) + fclose( p->pFile ); + FREE( p->pBuffer ); + Vec_PtrFree( p->vTokens ); + Vec_IntFree( p->vLines ); + free( p ); +} + +/**Function************************************************************* + + Synopsis [Returns the file size.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +char * Extra_FileReaderGetFileName( Extra_FileReader_t * p ) +{ + return p->pFileName; +} + +/**Function************************************************************* + + Synopsis [Returns the file size.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Extra_FileReaderGetFileSize( Extra_FileReader_t * p ) +{ + return p->nFileSize; +} + +/**Function************************************************************* + + Synopsis [Returns the current reading position.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Extra_FileReaderGetCurPosition( Extra_FileReader_t * p ) +{ + return p->nFileRead - (p->pBufferEnd - p->pBufferCur); +} + +/**Function************************************************************* + + Synopsis [Returns the line number for the given token.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Extra_FileReaderGetLineNumber( Extra_FileReader_t * p, int iToken ) +{ + assert( iToken >= 0 && iToken < p->vTokens->nSize ); + return p->vLines->pArray[iToken]; +} + + +/**Function************************************************************* + + Synopsis [Returns the next set of tokens.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void * Extra_FileReaderGetTokens( Extra_FileReader_t * p ) +{ + Vec_Ptr_t * vTokens; + while ( vTokens = Extra_FileReaderGetTokens_int( p ) ) + if ( vTokens->nSize > 0 ) + break; + return vTokens; +} + +/**Function************************************************************* + + Synopsis [Returns the next set of tokens.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void * Extra_FileReaderGetTokens_int( Extra_FileReader_t * p ) +{ + char * pChar; + int fTokenStarted, MapValue; + if ( p->fStop ) + return NULL; + // reset the token info + p->vTokens->nSize = 0; + p->vLines->nSize = 0; + fTokenStarted = 0; + // check if the new data should to be loaded + if ( p->pBufferCur > p->pBufferStop ) + Extra_FileReaderReload( p ); + +// printf( "%d\n", p->pBufferEnd - p->pBufferCur ); + + // process the string starting from the current position + for ( pChar = p->pBufferCur; pChar < p->pBufferEnd; pChar++ ) + { + // count the lines + if ( *pChar == '\n' ) + p->nLineCounter++; + // switch depending on the character + MapValue = p->pCharMap[*pChar]; + +// printf( "Char value = %d. Map value = %d.\n", *pChar, MapValue ); + + + switch ( MapValue ) + { + case EXTRA_CHAR_COMMENT: + if ( *pChar != '/' || *(pChar+1) == '/' ) + { // dealing with the need to have // as a comment + // if the token was being written, stop it + if ( fTokenStarted ) + fTokenStarted = 0; + // eraze the comment till the end of line + while ( *pChar != '\n' ) + { + *pChar++ = 0; + if ( pChar == p->pBufferEnd ) + { // this failure is due to the fact the comment continued + // through EXTRA_OFFSET_SIZE chars till the end of the buffer + printf( "Extra_FileReader failed to parse the file \"%s\".\n", p->pFileName ); + return NULL; + } + } + pChar--; + break; + } + // otherwise it is a normal character + case EXTRA_CHAR_NORMAL: + if ( !fTokenStarted ) + { + Vec_PtrPush( p->vTokens, pChar ); + Vec_IntPush( p->vLines, p->nLineCounter ); + fTokenStarted = 1; + } + break; + case EXTRA_CHAR_STOP: + if ( fTokenStarted ) + fTokenStarted = 0; + *pChar = 0; + // prepare before leaving + p->pBufferCur = pChar + 1; + return p->vTokens; + case EXTRA_CHAR_CLEAN: + if ( fTokenStarted ) + fTokenStarted = 0; + *pChar = 0; + break; + default: + assert( 0 ); + } + } + // the file is finished or the last part continued + // through EXTRA_OFFSET_SIZE chars till the end of the buffer + if ( p->pBufferStop == p->pBufferEnd ) // end of file + { + *pChar = 0; + p->fStop = 1; + return p->vTokens; + } + printf( "Extra_FileReader failed to parse the file \"%s\".\n", p->pFileName ); +/* + { + int i; + for ( i = 0; i < p->vTokens->nSize; i++ ) + printf( "%s ", p->vTokens->pArray[i] ); + printf( "\n" ); + } +*/ + return NULL; +} + +/**Function************************************************************* + + Synopsis [Loads new data into the file reader.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_FileReaderReload( Extra_FileReader_t * p ) +{ + int nCharsUsed, nCharsToRead; + assert( !p->fStop ); + assert( p->pBufferCur > p->pBufferStop ); + assert( p->pBufferCur < p->pBufferEnd ); + // figure out how many chars are still not processed + nCharsUsed = p->pBufferEnd - p->pBufferCur; + // move the remaining data to the beginning of the buffer + memmove( p->pBuffer, p->pBufferCur, nCharsUsed ); + p->pBufferCur = p->pBuffer; + // determine how many chars we will read + nCharsToRead = EXTRA_MINIMUM( p->nBufferSize - nCharsUsed, p->nFileSize - p->nFileRead ); + // read the chars + fread( p->pBuffer + nCharsUsed, nCharsToRead, 1, p->pFile ); + p->nFileRead += nCharsToRead; + // set the ponters to the end and the stopping point + p->pBufferEnd = p->pBuffer + nCharsUsed + nCharsToRead; + p->pBufferStop = (p->nFileRead == p->nFileSize)? p->pBufferEnd : p->pBuffer + EXTRA_BUFFER_SIZE - EXTRA_OFFSET_SIZE; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/misc/extra/extraUtilTruth.c b/src/misc/extra/extraUtilTruth.c new file mode 100644 index 00000000..3b0b16eb --- /dev/null +++ b/src/misc/extra/extraUtilTruth.c @@ -0,0 +1,1148 @@ +/**CFile**************************************************************** + + FileName [extraUtilMisc.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [extra] + + Synopsis [Various procedures for truth table manipulation.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: extraUtilMisc.c,v 1.0 2003/09/01 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "extra.h" + +/*---------------------------------------------------------------------------*/ +/* Constant declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Stucture declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Type declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Variable declarations */ +/*---------------------------------------------------------------------------*/ + +static unsigned s_VarMasks[5][2] = { + { 0x33333333, 0xAAAAAAAA }, + { 0x55555555, 0xCCCCCCCC }, + { 0x0F0F0F0F, 0xF0F0F0F0 }, + { 0x00FF00FF, 0xFF00FF00 }, + { 0x0000FFFF, 0xFFFF0000 } +}; + +/*---------------------------------------------------------------------------*/ +/* Macro declarations */ +/*---------------------------------------------------------------------------*/ + +/**AutomaticStart*************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Static function prototypes */ +/*---------------------------------------------------------------------------*/ + +/**AutomaticEnd***************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Definition of exported functions */ +/*---------------------------------------------------------------------------*/ + +/**Function************************************************************* + + Synopsis [Derive elementary truth tables.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +unsigned ** Extra_TruthElementary( int nVars ) +{ + unsigned ** pRes; + int i, k, nWords; + nWords = Extra_TruthWordNum(nVars); + pRes = (unsigned **)Extra_ArrayAlloc( nVars, nWords, 4 ); + for ( i = 0; i < nVars; i++ ) + { + if ( i < 5 ) + { + for ( k = 0; k < nWords; k++ ) + pRes[i][k] = s_VarMasks[i][1]; + } + else + { + for ( k = 0; k < nWords; k++ ) + if ( k & (1 << (i-5)) ) + pRes[i][k] = ~(unsigned)0; + else + pRes[i][k] = 0; + } + } + return pRes; +} + +/**Function************************************************************* + + Synopsis [Swaps two adjacent variables in the truth table.] + + Description [Swaps var number Start and var number Start+1 (0-based numbers). + The input truth table is pIn. The output truth table is pOut.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_TruthSwapAdjacentVars( unsigned * pOut, unsigned * pIn, int nVars, int iVar ) +{ + static unsigned PMasks[4][3] = { + { 0x99999999, 0x22222222, 0x44444444 }, + { 0xC3C3C3C3, 0x0C0C0C0C, 0x30303030 }, + { 0xF00FF00F, 0x00F000F0, 0x0F000F00 }, + { 0xFF0000FF, 0x0000FF00, 0x00FF0000 } + }; + int nWords = Extra_TruthWordNum( nVars ); + int i, k, Step, Shift; + + assert( iVar < nVars - 1 ); + if ( iVar < 4 ) + { + Shift = (1 << iVar); + for ( i = 0; i < nWords; i++ ) + pOut[i] = (pIn[i] & PMasks[iVar][0]) | ((pIn[i] & PMasks[iVar][1]) << Shift) | ((pIn[i] & PMasks[iVar][2]) >> Shift); + } + else if ( iVar > 4 ) + { + Step = (1 << (iVar - 5)); + for ( k = 0; k < nWords; k += 4*Step ) + { + for ( i = 0; i < Step; i++ ) + pOut[i] = pIn[i]; + for ( i = 0; i < Step; i++ ) + pOut[Step+i] = pIn[2*Step+i]; + for ( i = 0; i < Step; i++ ) + pOut[2*Step+i] = pIn[Step+i]; + for ( i = 0; i < Step; i++ ) + pOut[3*Step+i] = pIn[3*Step+i]; + pIn += 4*Step; + pOut += 4*Step; + } + } + else // if ( iVar == 4 ) + { + for ( i = 0; i < nWords; i += 2 ) + { + pOut[i] = (pIn[i] & 0x0000FFFF) | ((pIn[i+1] & 0x0000FFFF) << 16); + pOut[i+1] = (pIn[i+1] & 0xFFFF0000) | ((pIn[i] & 0xFFFF0000) >> 16); + } + } +} + +/**Function************************************************************* + + Synopsis [Swaps two adjacent variables in the truth table.] + + Description [Swaps var number Start and var number Start+1 (0-based numbers). + The input truth table is pIn. The output truth table is pOut.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_TruthSwapAdjacentVars2( unsigned * pIn, unsigned * pOut, int nVars, int Start ) +{ + int nWords = (nVars <= 5)? 1 : (1 << (nVars-5)); + int i, k, Step; + + assert( Start < nVars - 1 ); + switch ( Start ) + { + case 0: + for ( i = 0; i < nWords; i++ ) + pOut[i] = (pIn[i] & 0x99999999) | ((pIn[i] & 0x22222222) << 1) | ((pIn[i] & 0x44444444) >> 1); + return; + case 1: + for ( i = 0; i < nWords; i++ ) + pOut[i] = (pIn[i] & 0xC3C3C3C3) | ((pIn[i] & 0x0C0C0C0C) << 2) | ((pIn[i] & 0x30303030) >> 2); + return; + case 2: + for ( i = 0; i < nWords; i++ ) + pOut[i] = (pIn[i] & 0xF00FF00F) | ((pIn[i] & 0x00F000F0) << 4) | ((pIn[i] & 0x0F000F00) >> 4); + return; + case 3: + for ( i = 0; i < nWords; i++ ) + pOut[i] = (pIn[i] & 0xFF0000FF) | ((pIn[i] & 0x0000FF00) << 8) | ((pIn[i] & 0x00FF0000) >> 8); + return; + case 4: + for ( i = 0; i < nWords; i += 2 ) + { + pOut[i] = (pIn[i] & 0x0000FFFF) | ((pIn[i+1] & 0x0000FFFF) << 16); + pOut[i+1] = (pIn[i+1] & 0xFFFF0000) | ((pIn[i] & 0xFFFF0000) >> 16); + } + return; + default: + Step = (1 << (Start - 5)); + for ( k = 0; k < nWords; k += 4*Step ) + { + for ( i = 0; i < Step; i++ ) + pOut[i] = pIn[i]; + for ( i = 0; i < Step; i++ ) + pOut[Step+i] = pIn[2*Step+i]; + for ( i = 0; i < Step; i++ ) + pOut[2*Step+i] = pIn[Step+i]; + for ( i = 0; i < Step; i++ ) + pOut[3*Step+i] = pIn[3*Step+i]; + pIn += 4*Step; + pOut += 4*Step; + } + return; + } +} + +/**Function************************************************************* + + Synopsis [Expands the truth table according to the phase.] + + Description [The input and output truth tables are in pIn/pOut. The current number + of variables is nVars. The total number of variables in nVarsAll. The last argument + (Phase) contains shows where the variables should go.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_TruthStretch( unsigned * pOut, unsigned * pIn, int nVars, int nVarsAll, unsigned Phase ) +{ + unsigned * pTemp; + int i, k, Var = nVars - 1, Counter = 0; + for ( i = nVarsAll - 1; i >= 0; i-- ) + if ( Phase & (1 << i) ) + { + for ( k = Var; k < i; k++ ) + { + Extra_TruthSwapAdjacentVars( pOut, pIn, nVarsAll, k ); + pTemp = pIn; pIn = pOut; pOut = pTemp; + Counter++; + } + Var--; + } + assert( Var == -1 ); + // swap if it was moved an even number of times + if ( !(Counter & 1) ) + Extra_TruthCopy( pOut, pIn, nVarsAll ); +} + +/**Function************************************************************* + + Synopsis [Shrinks the truth table according to the phase.] + + Description [The input and output truth tables are in pIn/pOut. The current number + of variables is nVars. The total number of variables in nVarsAll. The last argument + (Phase) contains shows what variables should remain.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_TruthShrink( unsigned * pOut, unsigned * pIn, int nVars, int nVarsAll, unsigned Phase ) +{ + unsigned * pTemp; + int i, k, Var = 0, Counter = 0; + for ( i = 0; i < nVarsAll; i++ ) + if ( Phase & (1 << i) ) + { + for ( k = i-1; k >= Var; k-- ) + { + Extra_TruthSwapAdjacentVars( pOut, pIn, nVarsAll, k ); + pTemp = pIn; pIn = pOut; pOut = pTemp; + Counter++; + } + Var++; + } + assert( Var == nVars ); + // swap if it was moved an even number of times + if ( !(Counter & 1) ) + Extra_TruthCopy( pOut, pIn, nVarsAll ); +} + + +/**Function************************************************************* + + Synopsis [Returns 1 if TT depends on the given variable.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Extra_TruthVarInSupport( unsigned * pTruth, int nVars, int iVar ) +{ + int nWords = Extra_TruthWordNum( nVars ); + int i, k, Step; + + assert( iVar < nVars ); + switch ( iVar ) + { + case 0: + for ( i = 0; i < nWords; i++ ) + if ( (pTruth[i] & 0x55555555) != ((pTruth[i] & 0xAAAAAAAA) >> 1) ) + return 1; + return 0; + case 1: + for ( i = 0; i < nWords; i++ ) + if ( (pTruth[i] & 0x33333333) != ((pTruth[i] & 0xCCCCCCCC) >> 2) ) + return 1; + return 0; + case 2: + for ( i = 0; i < nWords; i++ ) + if ( (pTruth[i] & 0x0F0F0F0F) != ((pTruth[i] & 0xF0F0F0F0) >> 4) ) + return 1; + return 0; + case 3: + for ( i = 0; i < nWords; i++ ) + if ( (pTruth[i] & 0x00FF00FF) != ((pTruth[i] & 0xFF00FF00) >> 8) ) + return 1; + return 0; + case 4: + for ( i = 0; i < nWords; i++ ) + if ( (pTruth[i] & 0x0000FFFF) != ((pTruth[i] & 0xFFFF0000) >> 16) ) + return 1; + return 0; + default: + Step = (1 << (iVar - 5)); + for ( k = 0; k < nWords; k += 2*Step ) + { + for ( i = 0; i < Step; i++ ) + if ( pTruth[i] != pTruth[Step+i] ) + return 1; + pTruth += 2*Step; + } + return 0; + } +} + +/**Function************************************************************* + + Synopsis [Returns the number of support vars.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Extra_TruthSupportSize( unsigned * pTruth, int nVars ) +{ + int i, Counter = 0; + for ( i = 0; i < nVars; i++ ) + Counter += Extra_TruthVarInSupport( pTruth, nVars, i ); + return Counter; +} + +/**Function************************************************************* + + Synopsis [Returns support of the function.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Extra_TruthSupport( unsigned * pTruth, int nVars ) +{ + int i, Support = 0; + for ( i = 0; i < nVars; i++ ) + if ( Extra_TruthVarInSupport( pTruth, nVars, i ) ) + Support |= (1 << i); + return Support; +} + + + +/**Function************************************************************* + + Synopsis [Computes positive cofactor of the function.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_TruthCofactor1( unsigned * pTruth, int nVars, int iVar ) +{ + int nWords = Extra_TruthWordNum( nVars ); + int i, k, Step; + + assert( iVar < nVars ); + switch ( iVar ) + { + case 0: + for ( i = 0; i < nWords; i++ ) + pTruth[i] = (pTruth[i] & 0xAAAAAAAA) | ((pTruth[i] & 0xAAAAAAAA) >> 1); + return; + case 1: + for ( i = 0; i < nWords; i++ ) + pTruth[i] = (pTruth[i] & 0xCCCCCCCC) | ((pTruth[i] & 0xCCCCCCCC) >> 2); + return; + case 2: + for ( i = 0; i < nWords; i++ ) + pTruth[i] = (pTruth[i] & 0xF0F0F0F0) | ((pTruth[i] & 0xF0F0F0F0) >> 4); + return; + case 3: + for ( i = 0; i < nWords; i++ ) + pTruth[i] = (pTruth[i] & 0xFF00FF00) | ((pTruth[i] & 0xFF00FF00) >> 8); + return; + case 4: + for ( i = 0; i < nWords; i++ ) + pTruth[i] = (pTruth[i] & 0xFFFF0000) | ((pTruth[i] & 0xFFFF0000) >> 16); + return; + default: + Step = (1 << (iVar - 5)); + for ( k = 0; k < nWords; k += 2*Step ) + { + for ( i = 0; i < Step; i++ ) + pTruth[i] = pTruth[Step+i]; + pTruth += 2*Step; + } + return; + } +} + +/**Function************************************************************* + + Synopsis [Computes negative cofactor of the function.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_TruthCofactor0( unsigned * pTruth, int nVars, int iVar ) +{ + int nWords = Extra_TruthWordNum( nVars ); + int i, k, Step; + + assert( iVar < nVars ); + switch ( iVar ) + { + case 0: + for ( i = 0; i < nWords; i++ ) + pTruth[i] = (pTruth[i] & 0x55555555) | ((pTruth[i] & 0x55555555) << 1); + return; + case 1: + for ( i = 0; i < nWords; i++ ) + pTruth[i] = (pTruth[i] & 0x33333333) | ((pTruth[i] & 0x33333333) << 2); + return; + case 2: + for ( i = 0; i < nWords; i++ ) + pTruth[i] = (pTruth[i] & 0x0F0F0F0F) | ((pTruth[i] & 0x0F0F0F0F) << 4); + return; + case 3: + for ( i = 0; i < nWords; i++ ) + pTruth[i] = (pTruth[i] & 0x00FF00FF) | ((pTruth[i] & 0x00FF00FF) << 8); + return; + case 4: + for ( i = 0; i < nWords; i++ ) + pTruth[i] = (pTruth[i] & 0x0000FFFF) | ((pTruth[i] & 0x0000FFFF) << 16); + return; + default: + Step = (1 << (iVar - 5)); + for ( k = 0; k < nWords; k += 2*Step ) + { + for ( i = 0; i < Step; i++ ) + pTruth[Step+i] = pTruth[i]; + pTruth += 2*Step; + } + return; + } +} + + +/**Function************************************************************* + + Synopsis [Existentially quantifies the variable.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_TruthExist( unsigned * pTruth, int nVars, int iVar ) +{ + int nWords = Extra_TruthWordNum( nVars ); + int i, k, Step; + + assert( iVar < nVars ); + switch ( iVar ) + { + case 0: + for ( i = 0; i < nWords; i++ ) + pTruth[i] |= ((pTruth[i] & 0xAAAAAAAA) >> 1) | ((pTruth[i] & 0x55555555) << 1); + return; + case 1: + for ( i = 0; i < nWords; i++ ) + pTruth[i] |= ((pTruth[i] & 0xCCCCCCCC) >> 2) | ((pTruth[i] & 0x33333333) << 2); + return; + case 2: + for ( i = 0; i < nWords; i++ ) + pTruth[i] |= ((pTruth[i] & 0xF0F0F0F0) >> 4) | ((pTruth[i] & 0x0F0F0F0F) << 4); + return; + case 3: + for ( i = 0; i < nWords; i++ ) + pTruth[i] |= ((pTruth[i] & 0xFF00FF00) >> 8) | ((pTruth[i] & 0x00FF00FF) << 8); + return; + case 4: + for ( i = 0; i < nWords; i++ ) + pTruth[i] |= ((pTruth[i] & 0xFFFF0000) >> 16) | ((pTruth[i] & 0x0000FFFF) << 16); + return; + default: + Step = (1 << (iVar - 5)); + for ( k = 0; k < nWords; k += 2*Step ) + { + for ( i = 0; i < Step; i++ ) + { + pTruth[i] |= pTruth[Step+i]; + pTruth[Step+i] = pTruth[i]; + } + pTruth += 2*Step; + } + return; + } +} + +/**Function************************************************************* + + Synopsis [Existentially quantifies the variable.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_TruthForall( unsigned * pTruth, int nVars, int iVar ) +{ + int nWords = Extra_TruthWordNum( nVars ); + int i, k, Step; + + assert( iVar < nVars ); + switch ( iVar ) + { + case 0: + for ( i = 0; i < nWords; i++ ) + pTruth[i] &= ((pTruth[i] & 0xAAAAAAAA) >> 1) | ((pTruth[i] & 0x55555555) << 1); + return; + case 1: + for ( i = 0; i < nWords; i++ ) + pTruth[i] &= ((pTruth[i] & 0xCCCCCCCC) >> 2) | ((pTruth[i] & 0x33333333) << 2); + return; + case 2: + for ( i = 0; i < nWords; i++ ) + pTruth[i] &= ((pTruth[i] & 0xF0F0F0F0) >> 4) | ((pTruth[i] & 0x0F0F0F0F) << 4); + return; + case 3: + for ( i = 0; i < nWords; i++ ) + pTruth[i] &= ((pTruth[i] & 0xFF00FF00) >> 8) | ((pTruth[i] & 0x00FF00FF) << 8); + return; + case 4: + for ( i = 0; i < nWords; i++ ) + pTruth[i] &= ((pTruth[i] & 0xFFFF0000) >> 16) | ((pTruth[i] & 0x0000FFFF) << 16); + return; + default: + Step = (1 << (iVar - 5)); + for ( k = 0; k < nWords; k += 2*Step ) + { + for ( i = 0; i < Step; i++ ) + { + pTruth[i] &= pTruth[Step+i]; + pTruth[Step+i] = pTruth[i]; + } + pTruth += 2*Step; + } + return; + } +} + + +/**Function************************************************************* + + Synopsis [Computes negative cofactor of the function.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_TruthMux( unsigned * pOut, unsigned * pCof0, unsigned * pCof1, int nVars, int iVar ) +{ + int nWords = Extra_TruthWordNum( nVars ); + int i, k, Step; + + assert( iVar < nVars ); + switch ( iVar ) + { + case 0: + for ( i = 0; i < nWords; i++ ) + pOut[i] = (pCof0[i] & 0x55555555) | (pCof1[i] & 0xAAAAAAAA); + return; + case 1: + for ( i = 0; i < nWords; i++ ) + pOut[i] = (pCof0[i] & 0x33333333) | (pCof1[i] & 0xCCCCCCCC); + return; + case 2: + for ( i = 0; i < nWords; i++ ) + pOut[i] = (pCof0[i] & 0x0F0F0F0F) | (pCof1[i] & 0xF0F0F0F0); + return; + case 3: + for ( i = 0; i < nWords; i++ ) + pOut[i] = (pCof0[i] & 0x00FF00FF) | (pCof1[i] & 0xFF00FF00); + return; + case 4: + for ( i = 0; i < nWords; i++ ) + pOut[i] = (pCof0[i] & 0x0000FFFF) | (pCof1[i] & 0xFFFF0000); + return; + default: + Step = (1 << (iVar - 5)); + for ( k = 0; k < nWords; k += 2*Step ) + { + for ( i = 0; i < Step; i++ ) + { + pOut[i] = pCof0[i]; + pOut[Step+i] = pCof1[Step+i]; + } + pOut += 2*Step; + } + return; + } +} + +/**Function************************************************************* + + Synopsis [Checks symmetry of two variables.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Extra_TruthVarsSymm( unsigned * pTruth, int nVars, int iVar0, int iVar1 ) +{ + static unsigned uTemp0[16], uTemp1[16]; + assert( nVars <= 9 ); + // compute Cof01 + Extra_TruthCopy( uTemp0, pTruth, nVars ); + Extra_TruthCofactor0( uTemp0, nVars, iVar0 ); + Extra_TruthCofactor1( uTemp0, nVars, iVar1 ); + // compute Cof10 + Extra_TruthCopy( uTemp1, pTruth, nVars ); + Extra_TruthCofactor1( uTemp1, nVars, iVar0 ); + Extra_TruthCofactor0( uTemp1, nVars, iVar1 ); + // compare + return Extra_TruthIsEqual( uTemp0, uTemp1, nVars ); +} + +/**Function************************************************************* + + Synopsis [Checks antisymmetry of two variables.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Extra_TruthVarsAntiSymm( unsigned * pTruth, int nVars, int iVar0, int iVar1 ) +{ + static unsigned uTemp0[16], uTemp1[16]; + assert( nVars <= 9 ); + // compute Cof00 + Extra_TruthCopy( uTemp0, pTruth, nVars ); + Extra_TruthCofactor0( uTemp0, nVars, iVar0 ); + Extra_TruthCofactor0( uTemp0, nVars, iVar1 ); + // compute Cof11 + Extra_TruthCopy( uTemp1, pTruth, nVars ); + Extra_TruthCofactor1( uTemp1, nVars, iVar0 ); + Extra_TruthCofactor1( uTemp1, nVars, iVar1 ); + // compare + return Extra_TruthIsEqual( uTemp0, uTemp1, nVars ); +} + +/**Function************************************************************* + + Synopsis [Changes phase of the function w.r.t. one variable.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_TruthChangePhase( unsigned * pTruth, int nVars, int iVar ) +{ + int nWords = Extra_TruthWordNum( nVars ); + int i, k, Step; + unsigned Temp; + + assert( iVar < nVars ); + switch ( iVar ) + { + case 0: + for ( i = 0; i < nWords; i++ ) + pTruth[i] = ((pTruth[i] & 0x55555555) << 1) | ((pTruth[i] & 0xAAAAAAAA) >> 1); + return; + case 1: + for ( i = 0; i < nWords; i++ ) + pTruth[i] = ((pTruth[i] & 0x33333333) << 2) | ((pTruth[i] & 0xCCCCCCCC) >> 2); + return; + case 2: + for ( i = 0; i < nWords; i++ ) + pTruth[i] = ((pTruth[i] & 0x0F0F0F0F) << 4) | ((pTruth[i] & 0xF0F0F0F0) >> 4); + return; + case 3: + for ( i = 0; i < nWords; i++ ) + pTruth[i] = ((pTruth[i] & 0x00FF00FF) << 8) | ((pTruth[i] & 0xFF00FF00) >> 8); + return; + case 4: + for ( i = 0; i < nWords; i++ ) + pTruth[i] = ((pTruth[i] & 0x0000FFFF) << 16) | ((pTruth[i] & 0xFFFF0000) >> 16); + return; + default: + Step = (1 << (iVar - 5)); + for ( k = 0; k < nWords; k += 2*Step ) + { + for ( i = 0; i < Step; i++ ) + { + Temp = pTruth[i]; + pTruth[i] = pTruth[Step+i]; + pTruth[Step+i] = Temp; + } + pTruth += 2*Step; + } + return; + } +} + +/**Function************************************************************* + + Synopsis [Computes minimum overlap in supports of cofactors.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Extra_TruthMinCofSuppOverlap( unsigned * pTruth, int nVars, int * pVarMin ) +{ + static unsigned uCofactor[16]; + int i, ValueCur, ValueMin, VarMin; + unsigned uSupp0, uSupp1; + int nVars0, nVars1; + assert( nVars <= 9 ); + ValueMin = 32; + VarMin = -1; + for ( i = 0; i < nVars; i++ ) + { + // get negative cofactor + Extra_TruthCopy( uCofactor, pTruth, nVars ); + Extra_TruthCofactor0( uCofactor, nVars, i ); + uSupp0 = Extra_TruthSupport( uCofactor, nVars ); + nVars0 = Extra_WordCountOnes( uSupp0 ); +//Extra_PrintBinary( stdout, &uSupp0, 8 ); printf( "\n" ); + // get positive cofactor + Extra_TruthCopy( uCofactor, pTruth, nVars ); + Extra_TruthCofactor1( uCofactor, nVars, i ); + uSupp1 = Extra_TruthSupport( uCofactor, nVars ); + nVars1 = Extra_WordCountOnes( uSupp1 ); +//Extra_PrintBinary( stdout, &uSupp1, 8 ); printf( "\n" ); + // get the number of common vars + ValueCur = Extra_WordCountOnes( uSupp0 & uSupp1 ); + if ( ValueMin > ValueCur && nVars0 <= 5 && nVars1 <= 5 ) + { + ValueMin = ValueCur; + VarMin = i; + } + if ( ValueMin == 0 ) + break; + } + if ( pVarMin ) + *pVarMin = VarMin; + return ValueMin; +} + + +/**Function************************************************************* + + Synopsis [Counts the number of 1's in each cofactor.] + + Description [The resulting numbers are stored in the array of shorts, + whose length is 2*nVars. The number of 1's is counted in a different + space than the original function. For example, if the function depends + on k variables, the cofactors are assumed to depend on k-1 variables.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_TruthCountOnesInCofs( unsigned * pTruth, int nVars, short * pStore ) +{ + int nWords = Extra_TruthWordNum( nVars ); + int i, k, Counter; + memset( pStore, 0, sizeof(short) * 2 * nVars ); + if ( nVars <= 5 ) + { + if ( nVars > 0 ) + { + pStore[2*0+0] = Extra_WordCountOnes( pTruth[0] & 0x55555555 ); + pStore[2*0+1] = Extra_WordCountOnes( pTruth[0] & 0xAAAAAAAA ); + } + if ( nVars > 1 ) + { + pStore[2*1+0] = Extra_WordCountOnes( pTruth[0] & 0x33333333 ); + pStore[2*1+1] = Extra_WordCountOnes( pTruth[0] & 0xCCCCCCCC ); + } + if ( nVars > 2 ) + { + pStore[2*2+0] = Extra_WordCountOnes( pTruth[0] & 0x0F0F0F0F ); + pStore[2*2+1] = Extra_WordCountOnes( pTruth[0] & 0xF0F0F0F0 ); + } + if ( nVars > 3 ) + { + pStore[2*3+0] = Extra_WordCountOnes( pTruth[0] & 0x00FF00FF ); + pStore[2*3+1] = Extra_WordCountOnes( pTruth[0] & 0xFF00FF00 ); + } + if ( nVars > 4 ) + { + pStore[2*4+0] = Extra_WordCountOnes( pTruth[0] & 0x0000FFFF ); + pStore[2*4+1] = Extra_WordCountOnes( pTruth[0] & 0xFFFF0000 ); + } + return; + } + // nVars >= 6 + // count 1's for all other variables + for ( k = 0; k < nWords; k++ ) + { + Counter = Extra_WordCountOnes( pTruth[k] ); + for ( i = 5; i < nVars; i++ ) + if ( k & (1 << (i-5)) ) + pStore[2*i+1] += Counter; + else + pStore[2*i+0] += Counter; + } + // count 1's for the first five variables + for ( k = 0; k < nWords/2; k++ ) + { + pStore[2*0+0] += Extra_WordCountOnes( (pTruth[0] & 0x55555555) | ((pTruth[1] & 0x55555555) << 1) ); + pStore[2*0+1] += Extra_WordCountOnes( (pTruth[0] & 0xAAAAAAAA) | ((pTruth[1] & 0xAAAAAAAA) >> 1) ); + pStore[2*1+0] += Extra_WordCountOnes( (pTruth[0] & 0x33333333) | ((pTruth[1] & 0x33333333) << 2) ); + pStore[2*1+1] += Extra_WordCountOnes( (pTruth[0] & 0xCCCCCCCC) | ((pTruth[1] & 0xCCCCCCCC) >> 2) ); + pStore[2*2+0] += Extra_WordCountOnes( (pTruth[0] & 0x0F0F0F0F) | ((pTruth[1] & 0x0F0F0F0F) << 4) ); + pStore[2*2+1] += Extra_WordCountOnes( (pTruth[0] & 0xF0F0F0F0) | ((pTruth[1] & 0xF0F0F0F0) >> 4) ); + pStore[2*3+0] += Extra_WordCountOnes( (pTruth[0] & 0x00FF00FF) | ((pTruth[1] & 0x00FF00FF) << 8) ); + pStore[2*3+1] += Extra_WordCountOnes( (pTruth[0] & 0xFF00FF00) | ((pTruth[1] & 0xFF00FF00) >> 8) ); + pStore[2*4+0] += Extra_WordCountOnes( (pTruth[0] & 0x0000FFFF) | ((pTruth[1] & 0x0000FFFF) << 16) ); + pStore[2*4+1] += Extra_WordCountOnes( (pTruth[0] & 0xFFFF0000) | ((pTruth[1] & 0xFFFF0000) >> 16) ); + pTruth += 2; + } +} + + +/**Function************************************************************* + + Synopsis [Canonicize the truth table.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +unsigned Extra_TruthHash( unsigned * pIn, int nWords ) +{ + // The 1,024 smallest prime numbers used to compute the hash value + // http://www.math.utah.edu/~alfeld/math/primelist.html + static int HashPrimes[1024] = { 2, 3, 5, + 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, + 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, + 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, + 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, + 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, + 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, + 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, + 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, + 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, + 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, + 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, + 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, + 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, + 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, + 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, + 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, + 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, + 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, + 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, + 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, + 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, + 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, + 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, + 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693, + 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, + 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, + 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023, + 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, + 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, + 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361, 3371, 3373, + 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, + 3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, + 3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, + 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, 3823, 3833, + 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923, 3929, 3931, + 3943, 3947, 3967, 3989, 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, + 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177, + 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, + 4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423, + 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, + 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, + 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, 4759, 4783, 4787, 4789, + 4793, 4799, 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, + 4933, 4937, 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, + 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 5107, 5113, 5119, 5147, + 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279, + 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407, 5413, + 5417, 5419, 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, + 5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, 5641, 5647, + 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743, + 5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, + 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981, 5987, 6007, + 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, + 6131, 6133, 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, + 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 6337, 6343, + 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, + 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581, 6599, 6607, + 6619, 6637, 6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, + 6737, 6761, 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, 6841, 6857, + 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, 6949, 6959, 6961, 6967, 6971, + 6977, 6983, 6991, 6997, 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, + 7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, + 7237, 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, + 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, 7507, 7517, + 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573, 7577, 7583, 7589, 7591, 7603, + 7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, + 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, 7841, 7853, 7867, 7873, + 7877, 7879, 7883, 7901, 7907, 7919, 7927, 7933, 7937, 7949, 7951, 7963, 7993, 8009, + 8011, 8017, 8039, 8053, 8059, 8069, 8081, 8087, 8089, 8093, 8101, 8111, 8117, 8123, + 8147, 8161 }; + int i; + unsigned uHashKey; + assert( nWords <= 1024 ); + uHashKey = 0; + for ( i = 0; i < nWords; i++ ) + uHashKey ^= HashPrimes[i] * pIn[i]; + return uHashKey; +} + + +/**Function************************************************************* + + Synopsis [Canonicize the truth table.] + + Description [Returns the phase. ] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +unsigned Extra_TruthSemiCanonicize( unsigned * pInOut, unsigned * pAux, int nVars, char * pCanonPerm, short * pStore ) +{ + unsigned * pIn = pInOut, * pOut = pAux, * pTemp; + int nWords = Extra_TruthWordNum( nVars ); + int i, Temp, fChange, Counter, nOnes;//, k, j, w, Limit; + unsigned uCanonPhase; + + // canonicize output + uCanonPhase = 0; + nOnes = Extra_TruthCountOnes(pIn, nVars); + if ( (nOnes > nWords * 16) || ((nOnes == nWords * 16) && (pIn[0] & 1)) ) + { + uCanonPhase |= (1 << nVars); + Extra_TruthNot( pIn, pIn, nVars ); + } + + // collect the minterm counts + Extra_TruthCountOnesInCofs( pIn, nVars, pStore ); + + // canonicize phase + for ( i = 0; i < nVars; i++ ) + { + if ( pStore[2*i+0] <= pStore[2*i+1] ) + continue; + uCanonPhase |= (1 << i); + Temp = pStore[2*i+0]; + pStore[2*i+0] = pStore[2*i+1]; + pStore[2*i+1] = Temp; + Extra_TruthChangePhase( pIn, nVars, i ); + } + +// Extra_PrintHexadecimal( stdout, pIn, nVars ); +// printf( "\n" ); + + // permute + Counter = 0; + do { + fChange = 0; + for ( i = 0; i < nVars-1; i++ ) + { + if ( pStore[2*i] <= pStore[2*(i+1)] ) + continue; + Counter++; + fChange = 1; + + Temp = pCanonPerm[i]; + pCanonPerm[i] = pCanonPerm[i+1]; + pCanonPerm[i+1] = Temp; + + Temp = pStore[2*i]; + pStore[2*i] = pStore[2*(i+1)]; + pStore[2*(i+1)] = Temp; + + Temp = pStore[2*i+1]; + pStore[2*i+1] = pStore[2*(i+1)+1]; + pStore[2*(i+1)+1] = Temp; + + Extra_TruthSwapAdjacentVars( pOut, pIn, nVars, i ); + pTemp = pIn; pIn = pOut; pOut = pTemp; + } + } while ( fChange ); + +/* + Extra_PrintBinary( stdout, &uCanonPhase, nVars+1 ); printf( " : " ); + for ( i = 0; i < nVars; i++ ) + printf( "%d=%d/%d ", pCanonPerm[i], pStore[2*i], pStore[2*i+1] ); + printf( " C = %d\n", Counter ); + Extra_PrintHexadecimal( stdout, pIn, nVars ); + printf( "\n" ); +*/ + +/* + // process symmetric variable groups + uSymms = 0; + for ( i = 0; i < nVars-1; i++ ) + { + if ( pStore[2*i] != pStore[2*(i+1)] ) // i and i+1 cannot be symmetric + continue; + if ( pStore[2*i] != pStore[2*i+1] ) + continue; + if ( Extra_TruthVarsSymm( pIn, nVars, i, i+1 ) ) + continue; + if ( Extra_TruthVarsAntiSymm( pIn, nVars, i, i+1 ) ) + Extra_TruthChangePhase( pIn, nVars, i+1 ); + } +*/ + +/* + // process symmetric variable groups + uSymms = 0; + for ( i = 0; i < nVars-1; i++ ) + { + if ( pStore[2*i] != pStore[2*(i+1)] ) // i and i+1 cannot be symmetric + continue; + // i and i+1 can be symmetric + // find the end of this group + for ( k = i+1; k < nVars; k++ ) + if ( pStore[2*i] != pStore[2*k] ) + break; + Limit = k; + assert( i < Limit-1 ); + // go through the variables in this group + for ( j = i + 1; j < Limit; j++ ) + { + // check symmetry + if ( Extra_TruthVarsSymm( pIn, nVars, i, j ) ) + { + uSymms |= (1 << j); + continue; + } + // they are phase-unknown + if ( pStore[2*i] == pStore[2*i+1] ) + { + if ( Extra_TruthVarsAntiSymm( pIn, nVars, i, j ) ) + { + Extra_TruthChangePhase( pIn, nVars, j ); + uCanonPhase ^= (1 << j); + uSymms |= (1 << j); + continue; + } + } + + // they are not symmetric - move j as far as it goes in the group + for ( k = j; k < Limit-1; k++ ) + { + Counter++; + + Temp = pCanonPerm[k]; + pCanonPerm[k] = pCanonPerm[k+1]; + pCanonPerm[k+1] = Temp; + + assert( pStore[2*k] == pStore[2*(k+1)] ); + Extra_TruthSwapAdjacentVars( pOut, pIn, nVars, k ); + pTemp = pIn; pIn = pOut; pOut = pTemp; + } + Limit--; + j--; + } + i = Limit - 1; + } +*/ + + // swap if it was moved an even number of times + if ( Counter & 1 ) + Extra_TruthCopy( pOut, pIn, nVars ); + return uCanonPhase; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/misc/extra/extraUtilUtil.c b/src/misc/extra/extraUtilUtil.c new file mode 100644 index 00000000..ee0c400a --- /dev/null +++ b/src/misc/extra/extraUtilUtil.c @@ -0,0 +1,330 @@ +/**CFile**************************************************************** + + FileName [extraUtilUtil.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [extra] + + Synopsis [Old SIS utilities.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: extraUtilUtil.c,v 1.0 2003/02/01 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include +#include "extra.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +#define EXTRA_RLIMIT_DATA_DEFAULT 67108864 // assume 64MB by default + +/* File : getopt.c + * Author : Henry Spencer, University of Toronto + * Updated: 28 April 1984 + * + * Changes: (R Rudell) + * changed index() to strchr(); + * added getopt_reset() to reset the getopt argument parsing + * + * Purpose: get option letter from argv. + */ + +char * globalUtilOptarg; // Global argument pointer (util_optarg) +int globalUtilOptind = 0; // Global argv index (util_optind) + +static char *pScanStr; + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [util_cpu_time()] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +long Extra_CpuTime() +{ + return clock(); +} + +/**Function************************************************************* + + Synopsis [getSoftDataLimit()] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Extra_GetSoftDataLimit() +{ + return EXTRA_RLIMIT_DATA_DEFAULT; +} + +/**Function************************************************************* + + Synopsis [util_getopt_reset()] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_UtilGetoptReset() +{ + globalUtilOptarg = 0; + globalUtilOptind = 0; + pScanStr = 0; +} + +/**Function************************************************************* + + Synopsis [util_getopt()] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Extra_UtilGetopt( int argc, char *argv[], char *optstring ) +{ + register int c; + register char *place; + + globalUtilOptarg = NULL; + + if (pScanStr == NULL || *pScanStr == '\0') { + if (globalUtilOptind == 0) globalUtilOptind++; + if (globalUtilOptind >= argc) return EOF; + place = argv[globalUtilOptind]; + if (place[0] != '-' || place[1] == '\0') return EOF; + globalUtilOptind++; + if (place[1] == '-' && place[2] == '\0') return EOF; + pScanStr = place+1; + } + + c = *pScanStr++; + place = strchr(optstring, c); + if (place == NULL || c == ':') { + (void) fprintf(stderr, "%s: unknown option %c\n", argv[0], c); + return '?'; + } + if (*++place == ':') { + if (*pScanStr != '\0') { + globalUtilOptarg = pScanStr; + pScanStr = NULL; + } else { + if (globalUtilOptind >= argc) { + (void) fprintf(stderr, "%s: %c requires an argument\n", + argv[0], c); + return '?'; + } + globalUtilOptarg = argv[globalUtilOptind]; + globalUtilOptind++; + } + } + return c; +} + +/**Function************************************************************* + + Synopsis [util_print_time()] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +char * Extra_UtilPrintTime( long t ) +{ + static char s[40]; + + (void) sprintf(s, "%ld.%02ld sec", t/1000, (t%1000)/10); + return s; +} + + +/**Function************************************************************* + + Synopsis [Extra_UtilStrsav()] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +char * Extra_UtilStrsav( char *s ) +{ + if(s == NULL) { /* added 7/95, for robustness */ + return s; + } + else { + return strcpy(ALLOC(char, strlen(s)+1), s); + } +} + +/**Function************************************************************* + + Synopsis [util_tilde_expand()] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +char * Extra_UtilTildeExpand( char *fname ) +{ + return Extra_UtilStrsav( fname ); +} + +/**Function************************************************************* + + Synopsis [check_file()] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Extra_UtilCheckFile(char *filename, char *mode) +{ + FILE *fp; + int got_file; + + if (strcmp(mode, "x") == 0) { + mode = "r"; + } + fp = fopen(filename, mode); + got_file = (fp != 0); + if (fp != 0) { + (void) fclose(fp); + } + return got_file; +} + +/**Function************************************************************* + + Synopsis [util_file_search()] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +char * Extra_UtilFileSearch(char *file, char *path, char *mode) +//char *file; // file we're looking for +//char *path; // search path, colon separated +//char *mode; // "r", "w", or "x" +{ + int quit; + char *buffer, *filename, *save_path, *cp; + + if (path == 0 || strcmp(path, "") == 0) { + path = "."; /* just look in the current directory */ + } + + save_path = path = Extra_UtilStrsav(path); + quit = 0; + do { + cp = strchr(path, ':'); + if (cp != 0) { + *cp = '\0'; + } else { + quit = 1; + } + + /* cons up the filename out of the path and file name */ + if (strcmp(path, ".") == 0) { + buffer = Extra_UtilStrsav(file); + } else { + buffer = ALLOC(char, strlen(path) + strlen(file) + 4); + (void) sprintf(buffer, "%s/%s", path, file); + } + filename = Extra_UtilTildeExpand(buffer); + FREE(buffer); + + /* see if we can access it */ + if (Extra_UtilCheckFile(filename, mode)) { + FREE(save_path); + return filename; + } + FREE(filename); + path = ++cp; + } while (! quit); + + FREE(save_path); + return 0; +} + +/**Function************************************************************* + + Synopsis [MMout_of_memory()] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +/* MMout_of_memory -- out of memory for lazy people, flush and exit */ +void Extra_UtilMMout_Of_Memory( long size ) +{ + (void) fflush(stdout); + (void) fprintf(stderr, "\nout of memory allocating %u bytes\n", + (unsigned) size); + assert( 0 ); + exit(1); +} + +/**Function************************************************************* + + Synopsis [MMoutOfMemory()] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void (*Extra_UtilMMoutOfMemory)() = Extra_UtilMMout_Of_Memory; + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/misc/extra/module.make b/src/misc/extra/module.make new file mode 100644 index 00000000..ec8bca4d --- /dev/null +++ b/src/misc/extra/module.make @@ -0,0 +1,15 @@ +SRC += src/misc/extra/extraBddAuto.c \ + src/misc/extra/extraBddCas.c \ + src/misc/extra/extraBddKmap.c \ + src/misc/extra/extraBddMisc.c \ + src/misc/extra/extraBddSymm.c \ + src/misc/extra/extraBddUnate.c \ + src/misc/extra/extraUtilBitMatrix.c \ + src/misc/extra/extraUtilCanon.c \ + src/misc/extra/extraUtilFile.c \ + src/misc/extra/extraUtilMemory.c \ + src/misc/extra/extraUtilMisc.c \ + src/misc/extra/extraUtilProgress.c \ + src/misc/extra/extraUtilReader.c \ + src/misc/extra/extraUtilTruth.c \ + src/misc/extra/extraUtilUtil.c diff --git a/src/misc/hash/hash.h b/src/misc/hash/hash.h new file mode 100644 index 00000000..90e72868 --- /dev/null +++ b/src/misc/hash/hash.h @@ -0,0 +1,65 @@ +/**CFile**************************************************************** + + FileName [hash.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Hash map.] + + Synopsis [External declarations.] + + Author [Aaron P. Hurst] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - May 16, 2005.] + + Revision [$Id: vec.h,v 1.00 2005/06/20 00:00:00 ahurst Exp $] + +***********************************************************************/ + +#ifndef __HASH_H__ +#define __HASH_H__ + +//////////////////////////////////////////////////////////////////////// +/// INCLUDES /// +//////////////////////////////////////////////////////////////////////// + +#ifdef _WIN32 +#define inline __inline // compatible with MS VS 6.0 +#endif + +#include "hashInt.h" +#include "hashFlt.h" +#include "hashPtr.h" + +//////////////////////////////////////////////////////////////////////// +/// PARAMETERS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// BASIC TYPES /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// MACRO DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +#ifndef ABS +#define ABS(a) ((a) < 0 ? -(a) : (a)) +#endif + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +int Hash_DefaultHashFunc(int key, int nBins) { + return ABS( ( (key+11)*(key)*7+3 ) % nBins ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + +#endif + diff --git a/src/misc/hash/hashFlt.h b/src/misc/hash/hashFlt.h new file mode 100644 index 00000000..da20ee28 --- /dev/null +++ b/src/misc/hash/hashFlt.h @@ -0,0 +1,330 @@ +/**CFile**************************************************************** + + FileName [hashFlt.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Hash maps.] + + Synopsis [Hash maps.] + + Author [Aaron P. Hurst] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - May 16, 2006.] + + Revision [$Id: vecInt.h,v 1.00 2005/06/20 00:00:00 ahurst Exp $] + +***********************************************************************/ + +#ifndef __HASH_FLT_H__ +#define __HASH_FLT_H__ + +//////////////////////////////////////////////////////////////////////// +/// INCLUDES /// +//////////////////////////////////////////////////////////////////////// + +#include +#include "extra.h" + +extern int Hash_DefaultHashFunc(int key, int nBins); + +//////////////////////////////////////////////////////////////////////// +/// PARAMETERS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// BASIC TYPES /// +//////////////////////////////////////////////////////////////////////// + +typedef struct Hash_Flt_t_ Hash_Flt_t; +typedef struct Hash_Flt_Entry_t_ Hash_Flt_Entry_t; + +struct Hash_Flt_Entry_t_ +{ + int key; + float data; + struct Hash_Flt_Entry_t_ * pNext; +}; + +struct Hash_Flt_t_ +{ + int nSize; + int nBins; + int (* fHash)(int key, int nBins); + Hash_Flt_Entry_t ** pArray; +}; + + + +//////////////////////////////////////////////////////////////////////// +/// MACRO DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +#define Hash_FltForEachEntry( pHash, pEntry, bin) \ + for(bin=-1, pEntry=NULL; bin < pHash->nBins; (!pEntry)?(pEntry=pHash->pArray[++bin]):(pEntry=pEntry->pNext)) \ + if (pEntry) + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Allocates a hash map with the given number of bins.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Hash_Flt_t * Hash_FltAlloc( int nBins ) +{ + Hash_Flt_t * p; + int i; + assert(nBins > 0); + p = ALLOC( Hash_Flt_t, 1); + p->nBins = nBins; + p->fHash = Hash_DefaultHashFunc; + p->nSize = 0; + p->pArray = ALLOC( Hash_Flt_Entry_t *, nBins ); + for(i=0; ipArray[i] = NULL; + + return p; +} + +/**Function************************************************************* + + Synopsis [Returns 1 if a key already exists.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Hash_FltExists( Hash_Flt_t *p, int key ) +{ + int bin; + Hash_Flt_Entry_t *pEntry, **pLast; + + // find the bin where this key would live + bin = (*(p->fHash))(key, p->nBins); + + // search for key + pLast = &(p->pArray[bin]); + pEntry = p->pArray[bin]; + while(pEntry) { + if (pEntry->key == key) { + return 1; + } + pLast = &(pEntry->pNext); + pEntry = pEntry->pNext; + } + + return 0; +} + +/**Function************************************************************* + + Synopsis [Finds or creates an entry with a key and writes value.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Hash_FltWriteEntry( Hash_Flt_t *p, int key, float data ) +{ + int bin; + Hash_Flt_Entry_t *pEntry, **pLast; + + // find the bin where this key would live + bin = (*(p->fHash))(key, p->nBins); + + // search for key + pLast = &(p->pArray[bin]); + pEntry = p->pArray[bin]; + while(pEntry) { + if (pEntry->key == key) { + pEntry->data = data; + return; + } + pLast = &(pEntry->pNext); + pEntry = pEntry->pNext; + } + + // this key does not currently exist + // create a new entry and add to bin + p->nSize++; + (*pLast) = pEntry = ALLOC( Hash_Flt_Entry_t, 1 ); + pEntry->pNext = NULL; + pEntry->key = key; + pEntry->data = data; + + return; +} + + +/**Function************************************************************* + + Synopsis [Finds or creates an entry with a key.] + + Description [fCreate specifies whether new entries should be created.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline float Hash_FltEntry( Hash_Flt_t *p, int key, int fCreate ) +{ + int bin; + Hash_Flt_Entry_t *pEntry, **pLast; + + // find the bin where this key would live + bin = (*(p->fHash))(key, p->nBins); + + // search for key + pLast = &(p->pArray[bin]); + pEntry = p->pArray[bin]; + while(pEntry) { + if (pEntry->key == key) + return pEntry->data; + pLast = &(pEntry->pNext); + pEntry = pEntry->pNext; + } + + // this key does not currently exist + if (fCreate) { + // create a new entry and add to bin + p->nSize++; + (*pLast) = pEntry = ALLOC( Hash_Flt_Entry_t, 1 ); + pEntry->pNext = NULL; + pEntry->key = key; + pEntry->data = 0.0; + return pEntry->data; + } + + return 0.0; +} + + +/**Function************************************************************* + + Synopsis [Finds or creates an entry with a key and returns the pointer to it.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline float* Hash_FltEntryPtr( Hash_Flt_t *p, int key ) +{ + int bin; + Hash_Flt_Entry_t *pEntry, **pLast; + + // find the bin where this key would live + bin = (*(p->fHash))(key, p->nBins); + + // search for key + pLast = &(p->pArray[bin]); + pEntry = p->pArray[bin]; + while(pEntry) { + if (pEntry->key == key) + return &(pEntry->data); + pLast = &(pEntry->pNext); + pEntry = pEntry->pNext; + } + + // this key does not currently exist + // create a new entry and add to bin + p->nSize++; + (*pLast) = pEntry = ALLOC( Hash_Flt_Entry_t, 1 ); + pEntry->pNext = NULL; + pEntry->key = key; + pEntry->data = 0.0; + + return &(pEntry->data); +} + +/**Function************************************************************* + + Synopsis [Deletes an entry.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Hash_FltRemove( Hash_Flt_t *p, int key ) +{ + int bin; + Hash_Flt_Entry_t *pEntry, **pLast; + + // find the bin where this key would live + bin = (*(p->fHash))(key, p->nBins); + + // search for key + pLast = &(p->pArray[bin]); + pEntry = p->pArray[bin]; + while(pEntry) { + if (pEntry->key == key) { + p->nSize--; + *pLast = pEntry->pNext; + FREE( pEntry ); + return; + } + pLast = &(pEntry->pNext); + pEntry = pEntry->pNext; + } + + // could not find key + return; +} + +/**Function************************************************************* + + Synopsis [Frees the hash.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Hash_FltFree( Hash_Flt_t *p ) { + int bin; + Hash_Flt_Entry_t *pEntry; + + // free bins + for(bin = 0; bin < p->nBins; bin++) { + pEntry = p->pArray[bin]; + while(pEntry) { + pEntry = pEntry->pNext; + FREE( pEntry ); + } + } + + // free hash + FREE( p->pArray ); + FREE( p ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + +#endif diff --git a/src/misc/hash/hashInt.h b/src/misc/hash/hashInt.h new file mode 100644 index 00000000..3b91f5df --- /dev/null +++ b/src/misc/hash/hashInt.h @@ -0,0 +1,293 @@ +/**CFile**************************************************************** + + FileName [hashInt.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Hash maps.] + + Synopsis [Hash maps.] + + Author [Aaron P. Hurst] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - May 16, 2006.] + + Revision [$Id: vecInt.h,v 1.00 2005/06/20 00:00:00 ahurst Exp $] + +***********************************************************************/ + +#ifndef __HASH_INT_H__ +#define __HASH_INT_H__ + +//////////////////////////////////////////////////////////////////////// +/// INCLUDES /// +//////////////////////////////////////////////////////////////////////// + +#include +#include "extra.h" + +extern int Hash_DefaultHashFunc(int key, int nBins); + +//////////////////////////////////////////////////////////////////////// +/// PARAMETERS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// BASIC TYPES /// +//////////////////////////////////////////////////////////////////////// + +typedef struct Hash_Int_t_ Hash_Int_t; +typedef struct Hash_Int_Entry_t_ Hash_Int_Entry_t; + +struct Hash_Int_Entry_t_ +{ + int key; + int data; + struct Hash_Int_Entry_t_ * pNext; +}; + +struct Hash_Int_t_ +{ + int nSize; + int nBins; + int (* fHash)(int key, int nBins); + Hash_Int_Entry_t ** pArray; +}; + + + +//////////////////////////////////////////////////////////////////////// +/// MACRO DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +#define Hash_IntForEachEntry( pHash, pEntry, bin) \ + for(bin=-1, pEntry=NULL; bin < pHash->nBins; (!pEntry)?(pEntry=pHash->pArray[++bin]):(pEntry=pEntry->pNext)) \ + if (pEntry) + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Allocates a hash map with the given number of bins.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Hash_Int_t * Hash_IntAlloc( int nBins ) +{ + Hash_Int_t * p; + int i; + assert(nBins > 0); + p = ALLOC( Hash_Int_t, 1); + p->nBins = nBins; + p->fHash = Hash_DefaultHashFunc; + p->nSize = 0; + p->pArray = ALLOC( Hash_Int_Entry_t *, nBins ); + for(i=0; ipArray[i] = NULL; + + return p; +} + +/**Function************************************************************* + + Synopsis [Returns 1 if a key already exists.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Hash_IntExists( Hash_Int_t *p, int key) +{ + int bin; + Hash_Int_Entry_t *pEntry, **pLast; + + // find the bin where this key would live + bin = (*(p->fHash))(key, p->nBins); + + // search for key + pLast = &(p->pArray[bin]); + pEntry = p->pArray[bin]; + while(pEntry) { + if (pEntry->key == key) { + return 1; + } + pLast = &(pEntry->pNext); + pEntry = pEntry->pNext; + } + + return 0; +} + +/**Function************************************************************* + + Synopsis [Finds or creates an entry with a key and writes value.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Hash_IntWriteEntry( Hash_Int_t *p, int key, int data ) +{ + int bin; + Hash_Int_Entry_t *pEntry, **pLast; + + // find the bin where this key would live + bin = (*(p->fHash))(key, p->nBins); + + // search for key + pLast = &(p->pArray[bin]); + pEntry = p->pArray[bin]; + while(pEntry) { + if (pEntry->key == key) { + pEntry->data = data; + return; + } + pLast = &(pEntry->pNext); + pEntry = pEntry->pNext; + } + + // this key does not currently exist + // create a new entry and add to bin + p->nSize++; + (*pLast) = pEntry = ALLOC( Hash_Int_Entry_t, 1 ); + pEntry->pNext = NULL; + pEntry->key = key; + pEntry->data = data; + + return; +} + + +/**Function************************************************************* + + Synopsis [Finds or creates an entry with a key.] + + Description [fCreate specifies whether new entries will be created.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Hash_IntEntry( Hash_Int_t *p, int key, int fCreate ) +{ + int bin; + Hash_Int_Entry_t *pEntry, **pLast; + + // find the bin where this key would live + bin = (*(p->fHash))(key, p->nBins); + + // search for key + pLast = &(p->pArray[bin]); + pEntry = p->pArray[bin]; + while(pEntry) { + if (pEntry->key == key) + return pEntry->data; + pLast = &(pEntry->pNext); + pEntry = pEntry->pNext; + } + + // this key does not currently exist + if (fCreate) { + // create a new entry and add to bin + p->nSize++; + (*pLast) = pEntry = ALLOC( Hash_Int_Entry_t, 1 ); + pEntry->pNext = NULL; + pEntry->key = key; + pEntry->data = 0; + return pEntry->data; + } + + return 0; +} + + +/**Function************************************************************* + + Synopsis [Finds or creates an entry with a key and returns the pointer to it.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int* Hash_IntEntryPtr( Hash_Int_t *p, int key ) +{ + int bin; + Hash_Int_Entry_t *pEntry, **pLast; + + // find the bin where this key would live + bin = (*(p->fHash))(key, p->nBins); + + // search for key + pLast = &(p->pArray[bin]); + pEntry = p->pArray[bin]; + while(pEntry) { + if (pEntry->key == key) + return &(pEntry->data); + pLast = &(pEntry->pNext); + pEntry = pEntry->pNext; + } + + // this key does not currently exist + // create a new entry and add to bin + p->nSize++; + (*pLast) = pEntry = ALLOC( Hash_Int_Entry_t, 1 ); + pEntry->pNext = NULL; + pEntry->key = key; + pEntry->data = 0; + + return &(pEntry->data); +} + +/**Function************************************************************* + + Synopsis [Frees the hash.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Hash_IntFree( Hash_Int_t *p ) { + int bin; + Hash_Int_Entry_t *pEntry; + + // free bins + for(bin = 0; bin < p->nBins; bin++) { + pEntry = p->pArray[bin]; + while(pEntry) { + pEntry = pEntry->pNext; + FREE( pEntry ); + } + } + + // free hash + FREE( p->pArray ); + FREE( p ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + +#endif diff --git a/src/misc/hash/hashPtr.h b/src/misc/hash/hashPtr.h new file mode 100644 index 00000000..15398a8a --- /dev/null +++ b/src/misc/hash/hashPtr.h @@ -0,0 +1,331 @@ +/**CFile**************************************************************** + + FileName [hashFlt.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Hash maps.] + + Synopsis [Hash maps.] + + Author [Aaron P. Hurst] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - May 16, 2006.] + + Revision [$Id: vecInt.h,v 1.00 2005/06/20 00:00:00 ahurst Exp $] + +***********************************************************************/ + +#ifndef __HASH_PTR_H__ +#define __HASH_PTR_H__ + +//////////////////////////////////////////////////////////////////////// +/// INCLUDES /// +//////////////////////////////////////////////////////////////////////// + +#include +#include "extra.h" + +extern int Hash_DefaultHashFunc(int key, int nBins); + +//////////////////////////////////////////////////////////////////////// +/// PARAMETERS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// BASIC TYPES /// +//////////////////////////////////////////////////////////////////////// + +typedef struct Hash_Ptr_t_ Hash_Ptr_t; +typedef struct Hash_Ptr_Entry_t_ Hash_Ptr_Entry_t; + +struct Hash_Ptr_Entry_t_ +{ + int key; + void * data; + struct Hash_Ptr_Entry_t_ * pNext; +}; + +struct Hash_Ptr_t_ +{ + int nSize; + int nBins; + int (* fHash)(int key, int nBins); + Hash_Ptr_Entry_t ** pArray; +}; + + + +//////////////////////////////////////////////////////////////////////// +/// MACRO DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +#define Hash_PtrForEachEntry( pHash, pEntry, bin ) \ + for(bin=-1, pEntry=NULL; bin < pHash->nBins; (!pEntry)?(pEntry=pHash->pArray[++bin]):(pEntry=pEntry->pNext)) \ + if (pEntry) + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Allocates a hash map with the given number of bins.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Hash_Ptr_t * Hash_PtrAlloc( int nBins ) +{ + Hash_Ptr_t * p; + int i; + assert(nBins > 0); + p = ALLOC( Hash_Ptr_t, 1); + p->nBins = nBins; + p->fHash = Hash_DefaultHashFunc; + p->nSize = 0; + p->pArray = ALLOC( Hash_Ptr_Entry_t *, nBins ); + for(i=0; ipArray[i] = NULL; + + return p; +} + +/**Function************************************************************* + + Synopsis [Returns 1 if a key already exists.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Hash_PtrExists( Hash_Ptr_t *p, int key ) +{ + int bin; + Hash_Ptr_Entry_t *pEntry, **pLast; + + // find the bin where this key would live + bin = (*(p->fHash))(key, p->nBins); + + // search for key + pLast = &(p->pArray[bin]); + pEntry = p->pArray[bin]; + while(pEntry) { + if (pEntry->key == key) { + return 1; + } + pLast = &(pEntry->pNext); + pEntry = pEntry->pNext; + } + + return 0; +} + +/**Function************************************************************* + + Synopsis [Finds or creates an entry with a key and writes value.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Hash_PtrWriteEntry( Hash_Ptr_t *p, int key, void * data ) +{ + int bin; + Hash_Ptr_Entry_t *pEntry, **pLast; + + // find the bin where this key would live + bin = (*(p->fHash))(key, p->nBins); + + // search for key + pLast = &(p->pArray[bin]); + pEntry = p->pArray[bin]; + while(pEntry) { + if (pEntry->key == key) { + pEntry->data = data; + return; + } + pLast = &(pEntry->pNext); + pEntry = pEntry->pNext; + } + + // this key does not currently exist + // create a new entry and add to bin + p->nSize++; + (*pLast) = pEntry = ALLOC( Hash_Ptr_Entry_t, 1 ); + pEntry->pNext = NULL; + pEntry->key = key; + pEntry->data = data; + + return; +} + + +/**Function************************************************************* + + Synopsis [Finds or creates an entry with a key.] + + Description [fCreate specifies whether a new entry should be created.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void * Hash_PtrEntry( Hash_Ptr_t *p, int key, int fCreate ) +{ + int bin; + Hash_Ptr_Entry_t *pEntry, **pLast; + + // find the bin where this key would live + bin = (*(p->fHash))(key, p->nBins); + + // search for key + pLast = &(p->pArray[bin]); + pEntry = p->pArray[bin]; + while(pEntry) { + if (pEntry->key == key) + return pEntry->data; + pLast = &(pEntry->pNext); + pEntry = pEntry->pNext; + } + + // this key does not currently exist + if (fCreate) { + // create a new entry and add to bin + p->nSize++; + (*pLast) = pEntry = ALLOC( Hash_Ptr_Entry_t, 1 ); + pEntry->pNext = NULL; + pEntry->key = key; + pEntry->data = NULL; + return pEntry->data; + } + + return NULL; +} + + +/**Function************************************************************* + + Synopsis [Finds or creates an entry with a key and returns the pointer to it.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void** Hash_PtrEntryPtr( Hash_Ptr_t *p, int key ) +{ + int bin; + Hash_Ptr_Entry_t *pEntry, **pLast; + + // find the bin where this key would live + bin = (*(p->fHash))(key, p->nBins); + + // search for key + pLast = &(p->pArray[bin]); + pEntry = p->pArray[bin]; + while(pEntry) { + if (pEntry->key == key) + return &(pEntry->data); + pLast = &(pEntry->pNext); + pEntry = pEntry->pNext; + } + + // this key does not currently exist + // create a new entry and add to bin + p->nSize++; + (*pLast) = pEntry = ALLOC( Hash_Ptr_Entry_t, 1 ); + pEntry->pNext = NULL; + pEntry->key = key; + pEntry->data = NULL; + + return &(pEntry->data); +} + +/**Function************************************************************* + + Synopsis [Deletes an entry.] + + Description [Returns data, if there was any.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void* Hash_PtrRemove( Hash_Ptr_t *p, int key ) +{ + int bin; + void * data; + Hash_Ptr_Entry_t *pEntry, **pLast; + + // find the bin where this key would live + bin = (*(p->fHash))(key, p->nBins); + + // search for key + pLast = &(p->pArray[bin]); + pEntry = p->pArray[bin]; + while(pEntry) { + if (pEntry->key == key) { + p->nSize--; + data = pEntry->data; + *pLast = pEntry->pNext; + return data; + } + pLast = &(pEntry->pNext); + pEntry = pEntry->pNext; + } + + // could not find key + return NULL; +} + +/**Function************************************************************* + + Synopsis [Frees the hash.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Hash_PtrFree( Hash_Ptr_t *p ) { + int bin; + Hash_Ptr_Entry_t *pEntry; + + // free bins + for(bin = 0; bin < p->nBins; bin++) { + pEntry = p->pArray[bin]; + while(pEntry) { + pEntry = pEntry->pNext; + FREE( pEntry ); + } + } + + // free hash + FREE( p->pArray ); + FREE( p ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + +#endif diff --git a/src/misc/hash/module.make b/src/misc/hash/module.make new file mode 100644 index 00000000..d6d908e7 --- /dev/null +++ b/src/misc/hash/module.make @@ -0,0 +1 @@ +SRC += diff --git a/src/misc/mvc/module.make b/src/misc/mvc/module.make new file mode 100644 index 00000000..23735ca2 --- /dev/null +++ b/src/misc/mvc/module.make @@ -0,0 +1,16 @@ +SRC += src/misc/mvc/mvc.c \ + src/misc/mvc/mvcApi.c \ + src/misc/mvc/mvcCompare.c \ + src/misc/mvc/mvcContain.c \ + src/misc/mvc/mvcCover.c \ + src/misc/mvc/mvcCube.c \ + src/misc/mvc/mvcDivide.c \ + src/misc/mvc/mvcDivisor.c \ + src/misc/mvc/mvcList.c \ + src/misc/mvc/mvcLits.c \ + src/misc/mvc/mvcMan.c \ + src/misc/mvc/mvcOpAlg.c \ + src/misc/mvc/mvcOpBool.c \ + src/misc/mvc/mvcPrint.c \ + src/misc/mvc/mvcSort.c \ + src/misc/mvc/mvcUtils.c diff --git a/src/misc/mvc/mvc.c b/src/misc/mvc/mvc.c new file mode 100644 index 00000000..001b1c63 --- /dev/null +++ b/src/misc/mvc/mvc.c @@ -0,0 +1,46 @@ +/**CFile**************************************************************** + + FileName [mvc.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: mvc.c,v 1.3 2003/03/19 19:50:26 alanmi Exp $] + +***********************************************************************/ + +#include "mvc.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/misc/mvc/mvc.h b/src/misc/mvc/mvc.h new file mode 100644 index 00000000..70834e0a --- /dev/null +++ b/src/misc/mvc/mvc.h @@ -0,0 +1,732 @@ +/**CFile**************************************************************** + + FileName [mvc.h] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [Data structure for MV cube/cover manipulation.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: mvc.h,v 1.10 2003/05/02 23:23:59 wjiang Exp $] + +***********************************************************************/ + +#ifndef __MVC_H__ +#define __MVC_H__ + +//////////////////////////////////////////////////////////////////////// +/// INCLUDES /// +//////////////////////////////////////////////////////////////////////// + +#include +#include "extra.h" +#include "extra.h" + +//////////////////////////////////////////////////////////////////////// +/// PARAMETERS /// +//////////////////////////////////////////////////////////////////////// + +// this is the only part of Mvc package, which should be modified +// when compiling the package for other platforms + +// these parameters can be computed but setting them manually makes it faster +#define BITS_PER_WORD 32 // sizeof(Mvc_CubeWord_t) * 8 +#define BITS_PER_WORD_MINUS 31 // the same minus 1 +#define BITS_PER_WORD_LOG 5 // log2(sizeof(Mvc_CubeWord_t) * 8) +#define BITS_DISJOINT ((Mvc_CubeWord_t)0x55555555) // the mask of the type "01010101" +#define BITS_FULL ((Mvc_CubeWord_t)0xffffffff) // the mask of the type "11111111" + +// uncomment this macro to switch to standard memory management +//#define USE_SYSTEM_MEMORY_MANAGEMENT + +//////////////////////////////////////////////////////////////////////// +/// STRUCTURE DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +// cube/list/cover/data +typedef unsigned int Mvc_CubeWord_t; +typedef struct MvcCubeStruct Mvc_Cube_t; +typedef struct MvcListStruct Mvc_List_t; +typedef struct MvcCoverStruct Mvc_Cover_t; +typedef struct MvcDataStruct Mvc_Data_t; +typedef struct MvcManagerStruct Mvc_Manager_t; + +// the cube data structure +struct MvcCubeStruct +{ + Mvc_Cube_t * pNext; // the next cube in the linked list + unsigned iLast : 8; // the index of the last word + unsigned nUnused : 6; // the number of unused bits in the last word + unsigned fPrime : 1; // marks the prime cube + unsigned fEssen : 1; // marks the essential cube + unsigned nOnes : 16; // the number of 1's in the bit data + Mvc_CubeWord_t pData[1]; // the first Mvc_CubeWord_t filled with bit data +}; + +// the single-linked list of cubes in the cover +struct MvcListStruct +{ + Mvc_Cube_t * pHead; // the first cube in the list + Mvc_Cube_t * pTail; // the last cube in the list + int nItems; // the number of cubes in the list +}; + +// the cover data structure +struct MvcCoverStruct +{ + char nWords; // the number of machine words + char nUnused; // the number of unused bits in the last word + short nBits; // the number of used data bits in the cube + Mvc_List_t lCubes; // the single-linked list of cubes + Mvc_Cube_t ** pCubes; // the array of cubes (for sorting) + int nCubesAlloc; // the size of allocated storage + int * pLits; // the counter of lit occurrances in cubes + Mvc_Cube_t * pMask; // the multipurpose mask + Mvc_Manager_t * pMem; // the memory manager +}; + +// data structure to store information about MV variables +struct MvcDataStruct +{ + Mvc_Manager_t * pMan; // the memory manager +// Vm_VarMap_t * pVm; // the MV variable data + int nBinVars; // the number of binary variables + Mvc_Cube_t * pMaskBin; // the mask to select the binary bits only + Mvc_Cube_t ** ppMasks; // the mask to select each MV variable + Mvc_Cube_t * ppTemp[3]; // the temporary cubes +}; + +// the manager of covers and cubes (as of today, only managing memory) +struct MvcManagerStruct +{ + Extra_MmFixed_t * pManC; // the manager for covers + Extra_MmFixed_t * pMan1; // the manager for 1-word cubes + Extra_MmFixed_t * pMan2; // the manager for 2-word cubes + Extra_MmFixed_t * pMan4; // the manager for 3-word cubes +}; + +//////////////////////////////////////////////////////////////////////// +/// MACRO DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +// reading data from the header of the cube +#define Mvc_CubeReadNext(Cube) ((Cube)->pNext) +#define Mvc_CubeReadNextP(Cube) (&(Cube)->pNext) +#define Mvc_CubeReadLast(Cube) ((Cube)->iLast) +#define Mvc_CubeReadSize(Cube) ((Cube)->nOnes) +// setting data to the header of the cube +#define Mvc_CubeSetNext(Cube,Next) ((Cube)->pNext = (Next)) +#define Mvc_CubeSetLast(Cube,Last) ((Cube)->iLast = (Last)) +#define Mvc_CubeSetSize(Cube,Size) ((Cube)->nOnes = (Size)) +// checking the number of words + +#define Mvc_Cube1Words(Cube) ((Cube)->iLast == 0) +#define Mvc_Cube2Words(Cube) ((Cube)->iLast == 1) +#define Mvc_CubeNWords(Cube) ((Cube)->iLast > 1) +// getting one data bit +#define Mvc_CubeWhichWord(Bit) ((Bit) >> BITS_PER_WORD_LOG) +#define Mvc_CubeWhichBit(Bit) ((Bit) & BITS_PER_WORD_MINUS) +// accessing individual bits +#define Mvc_CubeBitValue(Cube, Bit) (((Cube)->pData[Mvc_CubeWhichWord(Bit)] & (((Mvc_CubeWord_t)1)<<(Mvc_CubeWhichBit(Bit)))) > 0) +#define Mvc_CubeBitInsert(Cube, Bit) ((Cube)->pData[Mvc_CubeWhichWord(Bit)] |= (((Mvc_CubeWord_t)1)<<(Mvc_CubeWhichBit(Bit)))) +#define Mvc_CubeBitRemove(Cube, Bit) ((Cube)->pData[Mvc_CubeWhichWord(Bit)] &= ~(((Mvc_CubeWord_t)1)<<(Mvc_CubeWhichBit(Bit)))) +// accessing values of the binary variables +#define Mvc_CubeVarValue(Cube, Var) (((Cube)->pData[Mvc_CubeWhichWord(2*(Var))] >> (Mvc_CubeWhichBit(2*(Var)))) & ((Mvc_CubeWord_t)3)) + +// various macros + +// cleaning the data bits of the cube +#define Mvc_Cube1BitClean( Cube )\ + ((Cube)->pData[0] = 0) +#define Mvc_Cube2BitClean( Cube )\ + (((Cube)->pData[0] = 0),\ + ((Cube)->pData[1] = 0)) +#define Mvc_CubeNBitClean( Cube )\ +{\ + int _i_;\ + for( _i_ = (Cube)->iLast; _i_ >= 0; _i_--)\ + (Cube)->pData[_i_] = 0;\ +} + +// cleaning the unused part of the lat word +#define Mvc_CubeBitCleanUnused( Cube )\ + ((Cube)->pData[(Cube)->iLast] &= (BITS_FULL >> (Cube)->nUnused)) + +// filling the used data bits with 1's +#define Mvc_Cube1BitFill( Cube )\ + (Cube)->pData[0] = (BITS_FULL >> (Cube)->nUnused); +#define Mvc_Cube2BitFill( Cube )\ + (((Cube)->pData[0] = BITS_FULL),\ + ((Cube)->pData[1] = (BITS_FULL >> (Cube)->nUnused))) +#define Mvc_CubeNBitFill( Cube )\ +{\ + int _i_;\ + (Cube)->pData[(Cube)->iLast] = (BITS_FULL >> (Cube)->nUnused);\ + for( _i_ = (Cube)->iLast - 1; _i_ >= 0; _i_-- )\ + (Cube)->pData[_i_] = BITS_FULL;\ +} + +// complementing the data bits +#define Mvc_Cube1BitNot( Cube )\ + ((Cube)->pData[0] ^= (BITS_FULL >> (Cube)->nUnused)) +#define Mvc_Cube2BitNot( Cube )\ + (((Cube)->pData[0] ^= BITS_FULL),\ + ((Cube)->pData[1] ^= (BITS_FULL >> (Cube)->nUnused))) +#define Mvc_CubeNBitNot( Cube )\ +{\ + int _i_;\ + (Cube)->pData[(Cube)->iLast] ^= (BITS_FULL >> (Cube)->nUnused);\ + for( _i_ = (Cube)->iLast - 1; _i_ >= 0; _i_-- )\ + (Cube)->pData[_i_] ^= BITS_FULL;\ +} + +#define Mvc_Cube1BitCopy( Cube1, Cube2 )\ + (((Cube1)->pData[0]) = ((Cube2)->pData[0])) +#define Mvc_Cube2BitCopy( Cube1, Cube2 )\ + ((((Cube1)->pData[0]) = ((Cube2)->pData[0])),\ + (((Cube1)->pData[1])= ((Cube2)->pData[1]))) +#define Mvc_CubeNBitCopy( Cube1, Cube2 )\ +{\ + int _i_;\ + for (_i_ = (Cube1)->iLast; _i_ >= 0; _i_--)\ + ((Cube1)->pData[_i_]) = ((Cube2)->pData[_i_]);\ +} + +#define Mvc_Cube1BitOr( CubeR, Cube1, Cube2 )\ + (((CubeR)->pData[0]) = ((Cube1)->pData[0] | (Cube2)->pData[0])) +#define Mvc_Cube2BitOr( CubeR, Cube1, Cube2 )\ + ((((CubeR)->pData[0]) = ((Cube1)->pData[0] | (Cube2)->pData[0])),\ + (((CubeR)->pData[1]) = ((Cube1)->pData[1] | (Cube2)->pData[1]))) +#define Mvc_CubeNBitOr( CubeR, Cube1, Cube2 )\ +{\ + int _i_;\ + for (_i_ = (Cube1)->iLast; _i_ >= 0; _i_--)\ + (((CubeR)->pData[_i_]) = ((Cube1)->pData[_i_] | (Cube2)->pData[_i_]));\ +} + +#define Mvc_Cube1BitExor( CubeR, Cube1, Cube2 )\ + (((CubeR)->pData[0]) = ((Cube1)->pData[0] ^ (Cube2)->pData[0])) +#define Mvc_Cube2BitExor( CubeR, Cube1, Cube2 )\ + ((((CubeR)->pData[0]) = ((Cube1)->pData[0] ^ (Cube2)->pData[0])),\ + (((CubeR)->pData[1]) = ((Cube1)->pData[1] ^ (Cube2)->pData[1]))) +#define Mvc_CubeNBitExor( CubeR, Cube1, Cube2 )\ +{\ + int _i_;\ + for (_i_ = (Cube1)->iLast; _i_ >= 0; _i_--)\ + (((CubeR)->pData[_i_]) = ((Cube1)->pData[_i_] ^ (Cube2)->pData[_i_]));\ +} + +#define Mvc_Cube1BitAnd( CubeR, Cube1, Cube2 )\ + (((CubeR)->pData[0]) = ((Cube1)->pData[0] & (Cube2)->pData[0])) +#define Mvc_Cube2BitAnd( CubeR, Cube1, Cube2 )\ + ((((CubeR)->pData[0]) = ((Cube1)->pData[0] & (Cube2)->pData[0])),\ + (((CubeR)->pData[1]) = ((Cube1)->pData[1] & (Cube2)->pData[1]))) +#define Mvc_CubeNBitAnd( CubeR, Cube1, Cube2 )\ +{\ + int _i_;\ + for (_i_ = (Cube1)->iLast; _i_ >= 0; _i_--)\ + (((CubeR)->pData[_i_]) = ((Cube1)->pData[_i_] & (Cube2)->pData[_i_]));\ +} + +#define Mvc_Cube1BitSharp( CubeR, Cube1, Cube2 )\ + (((CubeR)->pData[0]) = ((Cube1)->pData[0] & ~((Cube2)->pData[0]))) +#define Mvc_Cube2BitSharp( CubeR, Cube1, Cube2 )\ + ((((CubeR)->pData[0]) = ((Cube1)->pData[0] & ~((Cube2)->pData[0]))),\ + (((CubeR)->pData[1]) = ((Cube1)->pData[1] & ~((Cube2)->pData[1])))) +#define Mvc_CubeNBitSharp( CubeR, Cube1, Cube2 )\ +{\ + int _i_;\ + for (_i_ = (Cube1)->iLast; _i_ >= 0; _i_--)\ + (((CubeR)->pData[_i_]) = ((Cube1)->pData[_i_] & ~(Cube2)->pData[_i_]));\ +} + +#define Mvc_Cube1BitEmpty( Res, Cube )\ + (Res = ((Cube)->pData[0] == 0)) +#define Mvc_Cube2BitEmpty( Res, Cube )\ + (Res = ((Cube)->pData[0] == 0 && (Cube)->pData[1] == 0)) +#define Mvc_CubeNBitEmpty( Res, Cube )\ +{\ + int _i_; Res = 1;\ + for (_i_ = (Cube)->iLast; _i_ >= 0; _i_--)\ + if ( (Cube)->pData[_i_] )\ + { Res = 0; break; }\ +} + +#define Mvc_Cube1BitEqual( Res, Cube1, Cube2 )\ + (Res = (((Cube1)->pData[0]) == ((Cube2)->pData[0]))) +#define Mvc_Cube2BitEqual( Res, Cube1, Cube2 )\ + (Res = ((((Cube1)->pData[0]) == ((Cube2)->pData[0])) &&\ + (((Cube1)->pData[1]) == ((Cube2)->pData[1])))) +#define Mvc_CubeNBitEqual( Res, Cube1, Cube2 )\ +{\ + int _i_; Res = 1;\ + for (_i_ = (Cube1)->iLast; _i_ >= 0; _i_--)\ + if (((Cube1)->pData[_i_]) != ((Cube2)->pData[_i_]))\ + { Res = 0; break; }\ +} + +#define Mvc_Cube1BitLess( Res, Cube1, Cube2 )\ + (Res = (((Cube1)->pData[0]) < ((Cube2)->pData[0]))) +#define Mvc_Cube2BitLess( Res, Cube1, Cube2 )\ + (Res = ((((Cube1)->pData[0]) < ((Cube2)->pData[0])) ||\ + ((((Cube1)->pData[0]) == ((Cube2)->pData[0])) && (((Cube1)->pData[1]) < ((Cube2)->pData[1]))))) +#define Mvc_CubeNBitLess( Res, Cube1, Cube2 )\ +{\ + int _i_; Res = 1;\ + for (_i_ = (Cube1)->iLast; _i_ >= 0; _i_--)\ + if (((Cube1)->pData[_i_]) >= ((Cube2)->pData[_i_]))\ + { Res = 0; break; }\ +} + +#define Mvc_Cube1BitMore( Res, Cube1, Cube2 )\ + (Res = (((Cube1)->pData[0]) > ((Cube2)->pData[0]))) +#define Mvc_Cube2BitMore( Res, Cube1, Cube2 )\ + (Res = ((((Cube1)->pData[0]) > ((Cube2)->pData[0])) ||\ + ((((Cube1)->pData[0]) == ((Cube2)->pData[0])) && (((Cube1)->pData[1]) > ((Cube2)->pData[1]))))) +#define Mvc_CubeNBitMore( Res, Cube1, Cube2 )\ +{\ + int _i_; Res = 1;\ + for (_i_ = (Cube1)->iLast; _i_ >= 0; _i_--)\ + if (((Cube1)->pData[_i_]) <= ((Cube2)->pData[_i_]))\ + { Res = 0; break; }\ +} + +#define Mvc_Cube1BitNotImpl( Res, Cube1, Cube2 )\ + (Res = (((Cube1)->pData[0]) & ~((Cube2)->pData[0]))) +#define Mvc_Cube2BitNotImpl( Res, Cube1, Cube2 )\ + (Res = ((((Cube1)->pData[0]) & ~((Cube2)->pData[0])) ||\ + (((Cube1)->pData[1]) & ~((Cube2)->pData[1])))) +#define Mvc_CubeNBitNotImpl( Res, Cube1, Cube2 )\ +{\ + int _i_; Res = 0;\ + for (_i_ = (Cube1)->iLast; _i_ >= 0; _i_--)\ + if (((Cube1)->pData[_i_]) & ~((Cube2)->pData[_i_]))\ + { Res = 1; break; }\ +} + +#define Mvc_Cube1BitDisjoint( Res, Cube1, Cube2 )\ + (Res = ((((Cube1)->pData[0]) & ((Cube2)->pData[0])) == 0 )) +#define Mvc_Cube2BitDisjoint( Res, Cube1, Cube2 )\ + (Res = (((((Cube1)->pData[0]) & ((Cube2)->pData[0])) == 0 ) &&\ + ((((Cube1)->pData[1]) & ((Cube2)->pData[1])) == 0 ))) +#define Mvc_CubeNBitDisjoint( Res, Cube1, Cube2 )\ +{\ + int _i_; Res = 1;\ + for (_i_ = (Cube1)->iLast; _i_ >= 0; _i_--)\ + if (((Cube1)->pData[_i_]) & ((Cube2)->pData[_i_]))\ + { Res = 0; break; }\ +} + +#define Mvc_Cube1BitEqualUnderMask( Res, Cube1, Cube2, Mask )\ + (Res = ((((Cube1)->pData[0]) & ((Mask)->pData[0])) == (((Cube2)->pData[0]) & ((Mask)->pData[0])))) +#define Mvc_Cube2BitEqualUnderMask( Res, Cube1, Cube2, Mask )\ + (Res = (((((Cube1)->pData[0]) & ((Mask)->pData[0])) == (((Cube2)->pData[0]) & ((Mask)->pData[0]))) &&\ + ((((Cube1)->pData[1]) & ((Mask)->pData[1])) == (((Cube2)->pData[1]) & ((Mask)->pData[1]))))) +#define Mvc_CubeNBitEqualUnderMask( Res, Cube1, Cube2, Mask )\ +{\ + int _i_; Res = 1;\ + for (_i_ = (Cube1)->iLast; _i_ >= 0; _i_--)\ + if ((((Cube1)->pData[_i_]) & ((Mask)->pData[_i_])) != (((Cube2)->pData[_i_]) & ((Mask)->pData[_i_])))\ + { Res = 0; break; }\ +} + +#define Mvc_Cube1BitEqualOutsideMask( Res, Cube1, Cube2, Mask )\ + (Res = ((((Cube1)->pData[0]) | ((Mask)->pData[0])) == (((Cube2)->pData[0]) | ((Mask)->pData[0])))) +#define Mvc_Cube2BitEqualOutsideMask( Res, Cube1, Cube2, Mask )\ + (Res = (((((Cube1)->pData[0]) | ((Mask)->pData[0])) == (((Cube2)->pData[0]) | ((Mask)->pData[0]))) &&\ + ((((Cube1)->pData[1]) | ((Mask)->pData[1])) == (((Cube2)->pData[1]) | ((Mask)->pData[1]))))) +#define Mvc_CubeNBitEqualOutsideMask( Res, Cube1, Cube2, Mask )\ +{\ + int _i_; Res = 1;\ + for (_i_ = (Cube1)->iLast; _i_ >= 0; _i_--)\ + if ((((Cube1)->pData[_i_]) | ((Mask)->pData[_i_])) != (((Cube2)->pData[_i_]) | ((Mask)->pData[_i_])))\ + { Res = 0; break; }\ +} + +#define Mvc_Cube1BitIntersectUnderMask( Res, Cube1, Cube2, Mask)\ + (Res = ((((Cube1)->pData[0]) & ((Cube2)->pData[0]) & ((Mask)->pData[0])) > 0)) +#define Mvc_Cube2BitIntersectUnderMask( Res, Cube1, Cube2, Mask)\ + (Res = (((((Cube1)->pData[0]) & ((Cube2)->pData[0]) & ((Mask)->pData[0])) > 0) ||\ + ((((Cube1)->pData[1]) & ((Cube2)->pData[1]) & ((Mask)->pData[1])) > 0))) +#define Mvc_CubeNBitIntersectUnderMask( Res, Cube1, Cube2, Mask)\ +{\ + int _i_; Res = 0;\ + for (_i_ = (Cube1)->iLast; _i_ >= 0; _i_--)\ + if (((Cube1)->pData[_i_]) & ((Cube2)->pData[_i_]) & ((Mask)->pData[_i_]))\ + { Res = 1; break; }\ +} + +#define Mvc_Cube1BitNotImplUnderMask( Res, Cube1, Cube2, Mask )\ + (Res = (((Mask)->pData[0]) & ((Cube1)->pData[0]) & ~((Cube2)->pData[0]))) +#define Mvc_Cube2BitNotImplUnderMask( Res, Cube1, Cube2, Mask )\ + (Res = ((((Mask)->pData[0]) & ((Cube1)->pData[0]) & ~((Cube2)->pData[0])) ||\ + (((Mask)->pData[1]) & ((Cube1)->pData[1]) & ~((Cube2)->pData[1])))) +#define Mvc_CubeNBitNotImplUnderMask( Res, Cube1, Cube2, Mask )\ +{\ + int _i_; Res = 0;\ + for (_i_ = (Cube1)->iLast; _i_ >= 0; _i_--)\ + if (((Mask)->pData[_i_]) & ((Cube1)->pData[_i_]) & ~((Cube2)->pData[_i_]))\ + { Res = 1; break; }\ +} + +// the following macros make no assumption about the cube's bitset size +#define Mvc_CubeBitClean( Cube )\ + if ( Mvc_Cube1Words(Cube) ) { Mvc_Cube1BitClean( Cube ); }\ + else if ( Mvc_Cube2Words(Cube) ) { Mvc_Cube2BitClean( Cube ); }\ + else { Mvc_CubeNBitClean( Cube ); } +#define Mvc_CubeBitFill( Cube )\ + if ( Mvc_Cube1Words(Cube) ) { Mvc_Cube1BitFill( Cube ); }\ + else if ( Mvc_Cube2Words(Cube) ) { Mvc_Cube2BitFill( Cube ); }\ + else { Mvc_CubeNBitFill( Cube ); } +#define Mvc_CubeBitNot( Cube )\ + if ( Mvc_Cube1Words(Cube) ) { Mvc_Cube1BitNot( Cube ); }\ + else if ( Mvc_Cube2Words(Cube) ) { Mvc_Cube2BitNot( Cube ); }\ + else { Mvc_CubeNBitNot( Cube ); } +#define Mvc_CubeBitCopy( Cube1, Cube2 )\ + if ( Mvc_Cube1Words(Cube1) ) { Mvc_Cube1BitCopy( Cube1, Cube2 ); }\ + else if ( Mvc_Cube2Words(Cube1) ){ Mvc_Cube2BitCopy( Cube1, Cube2 ); }\ + else { Mvc_CubeNBitCopy( Cube1, Cube2 ); } +#define Mvc_CubeBitOr( CubeR, Cube1, Cube2 )\ + if ( Mvc_Cube1Words(Cube1) ) { Mvc_Cube1BitOr( CubeR, Cube1, Cube2 ); }\ + else if ( Mvc_Cube2Words(Cube1) ){ Mvc_Cube2BitOr( CubeR, Cube1, Cube2 ); }\ + else { Mvc_CubeNBitOr( CubeR, Cube1, Cube2 ); } +#define Mvc_CubeBitExor( CubeR, Cube1, Cube2 )\ + if ( Mvc_Cube1Words(Cube1) ) { Mvc_Cube1BitExor( CubeR, Cube1, Cube2 ); }\ + else if ( Mvc_Cube2Words(Cube1) ){ Mvc_Cube2BitExor( CubeR, Cube1, Cube2 ); }\ + else { Mvc_CubeNBitExor( CubeR, Cube1, Cube2 ); } +#define Mvc_CubeBitAnd( CubeR, Cube1, Cube2 )\ + if ( Mvc_Cube1Words(Cube1) ) { Mvc_Cube1BitAnd( CubeR, Cube1, Cube2 ); }\ + else if ( Mvc_Cube2Words(Cube1) ){ Mvc_Cube2BitAnd( CubeR, Cube1, Cube2 ); }\ + else { Mvc_CubeNBitAnd( CubeR, Cube1, Cube2 ); } +#define Mvc_CubeBitSharp( CubeR, Cube1, Cube2 )\ + if ( Mvc_Cube1Words(Cube1) ) { Mvc_Cube1BitSharp( CubeR, Cube1, Cube2 ); }\ + else if ( Mvc_Cube2Words(Cube1) ){ Mvc_Cube2BitSharp( CubeR, Cube1, Cube2 ); }\ + else { Mvc_CubeNBitSharp( CubeR, Cube1, Cube2 ); } +#define Mvc_CubeBitEmpty( Res, Cube )\ + if ( Mvc_Cube1Words(Cube) ) { Mvc_Cube1BitEmpty( Res, Cube ); }\ + else if ( Mvc_Cube2Words(Cube) ) { Mvc_Cube2BitEmpty( Res, Cube ); }\ + else { Mvc_CubeNBitEmpty( Res, Cube ); } +#define Mvc_CubeBitEqual( Res, Cube1, Cube2 )\ + if ( Mvc_Cube1Words(Cube1) ) { Mvc_Cube1BitEqual( Res, Cube1, Cube2 ); }\ + else if ( Mvc_Cube2Words(Cube1) ){ Mvc_Cube2BitEqual( Res, Cube1, Cube2 ); }\ + else { Mvc_CubeNBitEqual( Res, Cube1, Cube2 ); } +#define Mvc_CubeBitLess( Res, Cube1, Cube2 )\ + if ( Mvc_Cube1Words(Cube1) ) { Mvc_Cube1BitLess( Res, Cube1, Cube2 ); }\ + else if ( Mvc_Cube2Words(Cube1) ){ Mvc_Cube2BitLess( Res, Cube1, Cube2 ); }\ + else { Mvc_CubeNBitLess( Res, Cube1, Cube2 ); } +#define Mvc_CubeBitMore( Res, Cube1, Cube2 )\ + if ( Mvc_Cube1Words(Cube1) ) { Mvc_Cube1BitMore( Res, Cube1, Cube2 ); }\ + else if ( Mvc_Cube2Words(Cube1) ){ Mvc_Cube2BitMore( Res, Cube1, Cube2 ); }\ + else { Mvc_CubeNBitMore( Res, Cube1, Cube2 ); } +#define Mvc_CubeBitNotImpl( Res, Cube1, Cube2 )\ + if ( Mvc_Cube1Words(Cube1) ) { Mvc_Cube1BitNotImpl( Res, Cube1, Cube2 ); }\ + else if ( Mvc_Cube2Words(Cube1) ){ Mvc_Cube2BitNotImpl( Res, Cube1, Cube2 ); }\ + else { Mvc_CubeNBitNotImpl( Res, Cube1, Cube2 ); } +#define Mvc_CubeBitDisjoint( Res, Cube1, Cube2 )\ + if ( Mvc_Cube1Words(Cube1) ) { Mvc_Cube1BitDisjoint( Res, Cube1, Cube2 ); }\ + else if ( Mvc_Cube2Words(Cube1) ){ Mvc_Cube2BitDisjoint( Res, Cube1, Cube2 ); }\ + else { Mvc_CubeNBitDisjoint( Res, Cube1, Cube2 ); } +#define Mvc_CubeBitEqualUnderMask( Res, Cube1, Cube2, Mask )\ + if ( Mvc_Cube1Words(Cube1) ) { Mvc_Cube1BitEqualUnderMask( Res, Cube1, Cube2, Mask ); }\ + else if ( Mvc_Cube2Words(Cube1) ){ Mvc_Cube2BitEqualUnderMask( Res, Cube1, Cube2, Mask ); }\ + else { Mvc_CubeNBitEqualUnderMask( Res, Cube1, Cube2, Mask ); } +#define Mvc_CubeBitEqualOutsideMask( Res, Cube1, Cube2, Mask )\ + if ( Mvc_Cube1Words(Cube1) ) { Mvc_Cube1BitEqualOutsideMask( Res, Cube1, Cube2, Mask ); }\ + else if ( Mvc_Cube2Words(Cube1) ){ Mvc_Cube2BitEqualOutsideMask( Res, Cube1, Cube2, Mask ); }\ + else { Mvc_CubeNBitEqualOutsideMask( Res, Cube1, Cube2, Mask ); } +#define Mvc_CubeBitIntersectUnderMask( Res, Cube1, Cube2, Mask )\ + if ( Mvc_Cube1Words(Cube1) ) { Mvc_Cube1BitIntersectUnderMask( Res, Cube1, Cube2, Mask ); }\ + else if ( Mvc_Cube2Words(Cube1) ){ Mvc_Cube2BitIntersectUnderMask( Res, Cube1, Cube2, Mask ); }\ + else { Mvc_CubeNBitIntersectUnderMask( Res, Cube1, Cube2, Mask ); } +#define Mvc_CubeBitNotImplUnderMask( Res, Cube1, Cube2, Mask )\ + if ( Mvc_Cube1Words(Cube1) ) { Mvc_Cube1BitNotImplUnderMask( Res, Cube1, Cube2, Mask ); }\ + else if ( Mvc_Cube2Words(Cube1) ){ Mvc_Cube2BitNotImplUnderMask( Res, Cube1, Cube2, Mask ); }\ + else { Mvc_CubeNBitNotImplUnderMask( Res, Cube1, Cube2, Mask ); } + + +// managing linked lists +#define Mvc_ListAddCubeHead( pList, pCube )\ + {\ + if ( pList->pHead == NULL )\ + {\ + Mvc_CubeSetNext( pCube, NULL );\ + pList->pHead = pCube;\ + pList->pTail = pCube;\ + }\ + else\ + {\ + Mvc_CubeSetNext( pCube, pList->pHead );\ + pList->pHead = pCube;\ + }\ + pList->nItems++;\ + } +#define Mvc_ListAddCubeTail( pList, pCube )\ + {\ + if ( pList->pHead == NULL )\ + pList->pHead = pCube;\ + else\ + Mvc_CubeSetNext( pList->pTail, pCube );\ + pList->pTail = pCube;\ + Mvc_CubeSetNext( pCube, NULL );\ + pList->nItems++;\ + } +#define Mvc_ListDeleteCube( pList, pPrev, pCube )\ +{\ + if ( pPrev == NULL )\ + pList->pHead = pCube->pNext;\ + else\ + pPrev->pNext = pCube->pNext;\ + if ( pList->pTail == pCube )\ + {\ + assert( pCube->pNext == NULL );\ + pList->pTail = pPrev;\ + }\ + pList->nItems--;\ +} + +// managing linked lists inside the cover +#define Mvc_CoverAddCubeHead( pCover, pCube )\ +{\ + Mvc_List_t * pList = &pCover->lCubes;\ + Mvc_ListAddCubeHead( pList, pCube );\ +} +#define Mvc_CoverAddCubeTail( pCover, pCube )\ +{\ + Mvc_List_t * pList = &pCover->lCubes;\ + Mvc_ListAddCubeTail( pList, pCube );\ +} +#define Mvc_CoverDeleteCube( pCover, pPrev, pCube )\ +{\ + Mvc_List_t * pList = &pCover->lCubes;\ + Mvc_ListDeleteCube( pList, pPrev, pCube );\ +} + + + + + + +// iterator through the cubes in the cube list +#define Mvc_ListForEachCube( List, Cube )\ + for ( Cube = List->pHead;\ + Cube;\ + Cube = Cube->pNext ) +#define Mvc_ListForEachCubeSafe( List, Cube, Cube2 )\ + for ( Cube = List->pHead, Cube2 = (Cube? Cube->pNext: NULL);\ + Cube;\ + Cube = Cube2, Cube2 = (Cube? Cube->pNext: NULL) ) + +// iterator through cubes in the cover +#define Mvc_CoverForEachCube( Cover, Cube )\ + for ( Cube = (Cover)->lCubes.pHead;\ + Cube;\ + Cube = Cube->pNext ) +#define Mvc_CoverForEachCubeWithIndex( Cover, Cube, Index )\ + for ( Index = 0, Cube = (Cover)->lCubes.pHead;\ + Cube;\ + Index++, Cube = Cube->pNext ) +#define Mvc_CoverForEachCubeSafe( Cover, Cube, Cube2 )\ + for ( Cube = (Cover)->lCubes.pHead, Cube2 = (Cube? Cube->pNext: NULL);\ + Cube;\ + Cube = Cube2, Cube2 = (Cube? Cube->pNext: NULL) ) + +// iterator which starts from the given cube +#define Mvc_CoverForEachCubeStart( Start, Cube )\ + for ( Cube = Start;\ + Cube;\ + Cube = Cube->pNext ) +#define Mvc_CoverForEachCubeStartSafe( Start, Cube, Cube2 )\ + for ( Cube = Start, Cube2 = (Cube? Cube->pNext: NULL);\ + Cube;\ + Cube = Cube2, Cube2 = (Cube? Cube->pNext: NULL) ) + + +// iterator through literals of the cube +#define Mvc_CubeForEachBit( Cover, Cube, iBit, Value )\ + for ( iBit = 0;\ + iBit < Cover->nBits && ((Value = Mvc_CubeBitValue(Cube,iBit))>=0);\ + iBit++ ) +// iterator through values of binary variables +#define Mvc_CubeForEachVarValue( Cover, Cube, iVar, Value )\ + for ( iVar = 0;\ + iVar < Cover->nBits/2 && (Value = Mvc_CubeVarValue(Cube,iVar));\ + iVar++ ) + + +// macros which work with memory +// MEM_ALLOC: allocate the given number (Size) of items of type (Type) +// MEM_FREE: deallocate the pointer (Pointer) to the given number (Size) of items of type (Type) +#define MEM_ALLOC( Manager, Type, Size ) ((Type *)malloc( (Size) * sizeof(Type) )) +#define MEM_FREE( Manager, Type, Size, Pointer ) if ( Pointer ) { free(Pointer); Pointer = NULL; } + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/*=== mvcApi.c ====================================================*/ +extern int Mvc_CoverReadWordNum( Mvc_Cover_t * pCover ); +extern int Mvc_CoverReadBitNum( Mvc_Cover_t * pCover ); +extern int Mvc_CoverReadCubeNum( Mvc_Cover_t * pCover ); +extern Mvc_Cube_t * Mvc_CoverReadCubeHead( Mvc_Cover_t * pCover ); +extern Mvc_Cube_t * Mvc_CoverReadCubeTail( Mvc_Cover_t * pCover ); +extern Mvc_List_t * Mvc_CoverReadCubeList( Mvc_Cover_t * pCover ); +extern int Mvc_ListReadCubeNum( Mvc_List_t * pList ); +extern Mvc_Cube_t * Mvc_ListReadCubeHead( Mvc_List_t * pList ); +extern Mvc_Cube_t * Mvc_ListReadCubeTail( Mvc_List_t * pList ); +extern void Mvc_CoverSetCubeNum( Mvc_Cover_t * pCover,int nItems ); +extern void Mvc_CoverSetCubeHead( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube ); +extern void Mvc_CoverSetCubeTail( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube ); +extern void Mvc_CoverSetCubeList( Mvc_Cover_t * pCover, Mvc_List_t * pList ); +extern int Mvc_CoverIsEmpty( Mvc_Cover_t * pCover ); +extern int Mvc_CoverIsTautology( Mvc_Cover_t * pCover ); +extern int Mvc_CoverIsBinaryBuffer( Mvc_Cover_t * pCover ); +extern void Mvc_CoverMakeEmpty( Mvc_Cover_t * pCover ); +extern void Mvc_CoverMakeTautology( Mvc_Cover_t * pCover ); +extern Mvc_Cover_t * Mvc_CoverCreateEmpty( Mvc_Cover_t * pCover ); +extern Mvc_Cover_t * Mvc_CoverCreateTautology( Mvc_Cover_t * pCover ); +/*=== mvcCover.c ====================================================*/ +extern Mvc_Cover_t * Mvc_CoverAlloc( Mvc_Manager_t * pMem, int nBits ); +extern Mvc_Cover_t * Mvc_CoverCreateConst( Mvc_Manager_t * pMem, int nBits, int Phase ); +extern Mvc_Cover_t * Mvc_CoverClone( Mvc_Cover_t * pCover ); +extern Mvc_Cover_t * Mvc_CoverDup( Mvc_Cover_t * pCover ); +extern void Mvc_CoverFree( Mvc_Cover_t * pCover ); +extern void Mvc_CoverAllocateMask( Mvc_Cover_t * pCover ); +extern void Mvc_CoverAllocateArrayLits( Mvc_Cover_t * pCover ); +extern void Mvc_CoverAllocateArrayCubes( Mvc_Cover_t * pCover ); +extern void Mvc_CoverDeallocateMask( Mvc_Cover_t * pCover ); +extern void Mvc_CoverDeallocateArrayLits( Mvc_Cover_t * pCover ); +/*=== mvcCube.c ====================================================*/ +extern Mvc_Cube_t * Mvc_CubeAlloc( Mvc_Cover_t * pCover ); +extern Mvc_Cube_t * Mvc_CubeDup( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube ); +extern void Mvc_CubeFree( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube ); +extern void Mvc_CubeBitRemoveDcs( Mvc_Cube_t * pCube ); +/*=== mvcCompare.c ====================================================*/ +extern int Mvc_CubeCompareInt( Mvc_Cube_t * pC1, Mvc_Cube_t * pC2, Mvc_Cube_t * pMask ); +extern int Mvc_CubeCompareSizeAndInt( Mvc_Cube_t * pC1, Mvc_Cube_t * pC2, Mvc_Cube_t * pMask ); +extern int Mvc_CubeCompareIntUnderMask( Mvc_Cube_t * pC1, Mvc_Cube_t * pC2, Mvc_Cube_t * pMask ); +extern int Mvc_CubeCompareIntOutsideMask( Mvc_Cube_t * pC1, Mvc_Cube_t * pC2, Mvc_Cube_t * pMask ); +extern int Mvc_CubeCompareIntOutsideAndUnderMask( Mvc_Cube_t * pC1, Mvc_Cube_t * pC2, Mvc_Cube_t * pMask ); +/*=== mvcDd.c ====================================================*/ +/* +extern DdNode * Mvc_CoverConvertToBdd( DdManager * dd, Mvc_Cover_t * pCover ); +extern DdNode * Mvc_CoverConvertToZdd( DdManager * dd, Mvc_Cover_t * pCover ); +extern DdNode * Mvc_CoverConvertToZdd2( DdManager * dd, Mvc_Cover_t * pCover ); +extern DdNode * Mvc_CubeConvertToBdd( DdManager * dd, Mvc_Cube_t * pCube ); +extern DdNode * Mvc_CubeConvertToZdd( DdManager * dd, Mvc_Cube_t * pCube ); +extern DdNode * Mvc_CubeConvertToZdd2( DdManager * dd, Mvc_Cube_t * pCube ); +*/ +/*=== mvcDivisor.c ====================================================*/ +extern Mvc_Cover_t * Mvc_CoverDivisor( Mvc_Cover_t * pCover ); +/*=== mvcDivide.c ====================================================*/ +extern void Mvc_CoverDivide( Mvc_Cover_t * pCover, Mvc_Cover_t * pDiv, Mvc_Cover_t ** ppQuo, Mvc_Cover_t ** ppRem ); +extern void Mvc_CoverDivideInternal( Mvc_Cover_t * pCover, Mvc_Cover_t * pDiv, Mvc_Cover_t ** ppQuo, Mvc_Cover_t ** ppRem ); +extern void Mvc_CoverDivideByLiteral( Mvc_Cover_t * pCover, Mvc_Cover_t * pDiv, Mvc_Cover_t ** ppQuo, Mvc_Cover_t ** ppRem ); +extern void Mvc_CoverDivideByCube( Mvc_Cover_t * pCover, Mvc_Cover_t * pDiv, Mvc_Cover_t ** ppQuo, Mvc_Cover_t ** ppRem ); +extern void Mvc_CoverDivideByLiteralQuo( Mvc_Cover_t * pCover, int iLit ); +/*=== mvcList.c ====================================================*/ +// these functions are available as macros +extern void Mvc_ListAddCubeHead_( Mvc_List_t * pList, Mvc_Cube_t * pCube ); +extern void Mvc_ListAddCubeTail_( Mvc_List_t * pList, Mvc_Cube_t * pCube ); +extern void Mvc_ListDeleteCube_( Mvc_List_t * pList, Mvc_Cube_t * pPrev, Mvc_Cube_t * pCube ); +extern void Mvc_CoverAddCubeHead_( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube ); +extern void Mvc_CoverAddCubeTail_( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube ); +extern void Mvc_CoverDeleteCube_( Mvc_Cover_t * pCover, Mvc_Cube_t * pPrev, Mvc_Cube_t * pCube ); +extern void Mvc_CoverAddDupCubeHead( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube ); +extern void Mvc_CoverAddDupCubeTail( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube ); +// other functions +extern void Mvc_CoverAddLiteralsOfCube( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube ); +extern void Mvc_CoverDeleteLiteralsOfCube( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube ); +extern void Mvc_CoverList2Array( Mvc_Cover_t * pCover ); +extern void Mvc_CoverArray2List( Mvc_Cover_t * pCover ); +extern Mvc_Cube_t * Mvc_ListGetTailFromHead( Mvc_Cube_t * pHead ); +/*=== mvcPrint.c ====================================================*/ +extern void Mvc_CoverPrint( Mvc_Cover_t * pCover ); +extern void Mvc_CubePrint( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube ); +extern void Mvc_CoverPrintMv( Mvc_Data_t * pData, Mvc_Cover_t * pCover ); +extern void Mvc_CubePrintMv( Mvc_Data_t * pData, Mvc_Cover_t * pCover, Mvc_Cube_t * pCube ); +/*=== mvcSort.c ====================================================*/ +extern void Mvc_CoverSort( Mvc_Cover_t * pCover, Mvc_Cube_t * pMask, int (* pCompareFunc)(Mvc_Cube_t *, Mvc_Cube_t *, Mvc_Cube_t *) ); +/*=== mvcUtils.c ====================================================*/ +extern void Mvc_CoverSupport( Mvc_Cover_t * pCover, Mvc_Cube_t * pSupp ); +extern int Mvc_CoverSupportSizeBinary( Mvc_Cover_t * pCover ); +extern int Mvc_CoverSupportVarBelongs( Mvc_Cover_t * pCover, int iVar ); +extern void Mvc_CoverCommonCube( Mvc_Cover_t * pCover, Mvc_Cube_t * pComCube ); +extern int Mvc_CoverIsCubeFree( Mvc_Cover_t * pCover ); +extern void Mvc_CoverMakeCubeFree( Mvc_Cover_t * pCover ); +extern Mvc_Cover_t * Mvc_CoverCommonCubeCover( Mvc_Cover_t * pCover ); +extern int Mvc_CoverCheckSuppContainment( Mvc_Cover_t * pCover1, Mvc_Cover_t * pCover2 ); +extern int Mvc_CoverSetCubeSizes( Mvc_Cover_t * pCover ); +extern int Mvc_CoverGetCubeSize( Mvc_Cube_t * pCube ); +extern int Mvc_CoverCountCubePairDiffs( Mvc_Cover_t * pCover, unsigned char pDiffs[] ); +extern Mvc_Cover_t * Mvc_CoverRemap( Mvc_Cover_t * pCover, int * pVarsRem, int nVarsRem ); +extern void Mvc_CoverInverse( Mvc_Cover_t * pCover ); +extern Mvc_Cover_t * Mvc_CoverRemoveDontCareLits( Mvc_Cover_t * pCover ); +extern Mvc_Cover_t * Mvc_CoverCofactor( Mvc_Cover_t * pCover, int iValue, int iValueOther ); +extern Mvc_Cover_t * Mvc_CoverFlipVar( Mvc_Cover_t * pCover, int iValue0, int iValue1 ); +extern Mvc_Cover_t * Mvc_CoverUnivQuantify( Mvc_Cover_t * p, int iValueA0, int iValueA1, int iValueB0, int iValueB1 ); +extern Mvc_Cover_t ** Mvc_CoverCofactors( Mvc_Data_t * pData, Mvc_Cover_t * pCover, int iVar ); +extern int Mvr_CoverCountLitsWithValue( Mvc_Data_t * pData, Mvc_Cover_t * pCover, int iVar, int iValue ); +//extern Mvc_Cover_t * Mvc_CoverCreateExpanded( Mvc_Cover_t * pCover, Vm_VarMap_t * pVmNew ); +extern Mvc_Cover_t * Mvc_CoverTranspose( Mvc_Cover_t * pCover ); +extern int Mvc_UtilsCheckUnusedZeros( Mvc_Cover_t * pCover ); +/*=== mvcLits.c ====================================================*/ +extern int Mvc_CoverAnyLiteral( Mvc_Cover_t * pCover, Mvc_Cube_t * pMask ); +extern int Mvc_CoverBestLiteral( Mvc_Cover_t * pCover, Mvc_Cube_t * pMask ); +extern int Mvc_CoverWorstLiteral( Mvc_Cover_t * pCover, Mvc_Cube_t * pMask ); +extern Mvc_Cover_t * Mvc_CoverBestLiteralCover( Mvc_Cover_t * pCover, Mvc_Cover_t * pSimple ); +extern int Mvc_CoverFirstCubeFirstLit( Mvc_Cover_t * pCover ); +extern int Mvc_CoverCountLiterals( Mvc_Cover_t * pCover ); +extern int Mvc_CoverIsOneLiteral( Mvc_Cover_t * pCover ); +/*=== mvcOpAlg.c ====================================================*/ +extern Mvc_Cover_t * Mvc_CoverAlgebraicMultiply( Mvc_Cover_t * pCover1, Mvc_Cover_t * pCover2 ); +extern Mvc_Cover_t * Mvc_CoverAlgebraicSubtract( Mvc_Cover_t * pCover1, Mvc_Cover_t * pCover2 ); +extern int Mvc_CoverAlgebraicEqual( Mvc_Cover_t * pCover1, Mvc_Cover_t * pCover2 ); +/*=== mvcOpBool.c ====================================================*/ +extern Mvc_Cover_t * Mvc_CoverBooleanOr( Mvc_Cover_t * pCover1, Mvc_Cover_t * pCover2 ); +extern Mvc_Cover_t * Mvc_CoverBooleanAnd( Mvc_Data_t * p, Mvc_Cover_t * pCover1, Mvc_Cover_t * pCover2 ); +extern int Mvc_CoverBooleanEqual( Mvc_Data_t * p, Mvc_Cover_t * pCover1, Mvc_Cover_t * pCover2 ); + +/*=== mvcContain.c ====================================================*/ +extern int Mvc_CoverContain( Mvc_Cover_t * pCover ); +/*=== mvcTau.c ====================================================*/ +extern int Mvc_CoverTautology( Mvc_Data_t * p, Mvc_Cover_t * pCover ); +/*=== mvcCompl.c ====================================================*/ +extern Mvc_Cover_t * Mvc_CoverComplement( Mvc_Data_t * p, Mvc_Cover_t * pCover ); +/*=== mvcSharp.c ====================================================*/ +extern Mvc_Cover_t * Mvc_CoverSharp( Mvc_Data_t * p, Mvc_Cover_t * pA, Mvc_Cover_t * pB ); +extern int Mvc_CoverDist0Cubes( Mvc_Data_t * pData, Mvc_Cube_t * pA, Mvc_Cube_t * pB ); +extern void Mvc_CoverIntersectCubes( Mvc_Data_t * pData, Mvc_Cover_t * pC1, Mvc_Cover_t * pC2 ); +extern int Mvc_CoverIsIntersecting( Mvc_Data_t * pData, Mvc_Cover_t * pC1, Mvc_Cover_t * pC2 ); +extern void Mvc_CoverAppendCubes( Mvc_Cover_t * pC1, Mvc_Cover_t * pC2 ); +extern void Mvc_CoverCopyAndAppendCubes( Mvc_Cover_t * pC1, Mvc_Cover_t * pC2 ); +extern void Mvc_CoverRemoveCubes( Mvc_Cover_t * pC ); + +/*=== mvcReshape.c ====================================================*/ +extern void Mvc_CoverMinimizeByReshape( Mvc_Data_t * pData, Mvc_Cover_t * pCover ); + +/*=== mvcMerge.c ====================================================*/ +extern void Mvc_CoverDist1Merge( Mvc_Data_t * p, Mvc_Cover_t * pCover ); + +/*=== mvcData.c ====================================================*/ +//extern Mvc_Data_t * Mvc_CoverDataAlloc( Vm_VarMap_t * pVm, Mvc_Cover_t * pCover ); +//extern void Mvc_CoverDataFree( Mvc_Data_t * p, Mvc_Cover_t * pCover ); + +/*=== mvcMan.c ====================================================*/ +extern void Mvc_ManagerFree( Mvc_Manager_t * p ); +extern Mvc_Manager_t * Mvc_ManagerStart(); +extern Mvc_Manager_t * Mvc_ManagerAllocCover(); +extern Mvc_Manager_t * Mvc_ManagerAllocCube( int nWords ); +extern Mvc_Manager_t * Mvc_ManagerFreeCover( Mvc_Cover_t * pCover ); +extern Mvc_Manager_t * Mvc_ManagerFreeCube( Mvc_Cover_t * pCube, int nWords ); + +#endif + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + diff --git a/src/misc/mvc/mvcApi.c b/src/misc/mvc/mvcApi.c new file mode 100644 index 00000000..eb942f93 --- /dev/null +++ b/src/misc/mvc/mvcApi.c @@ -0,0 +1,233 @@ +/**CFile**************************************************************** + + FileName [mvcApi.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: mvcApi.c,v 1.4 2003/04/03 06:31:48 alanmi Exp $] + +***********************************************************************/ + +#include "mvc.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Mvc_CoverReadWordNum( Mvc_Cover_t * pCover ) { return pCover->nWords; } +int Mvc_CoverReadBitNum( Mvc_Cover_t * pCover ) { return pCover->nBits; } +int Mvc_CoverReadCubeNum( Mvc_Cover_t * pCover ) { return pCover->lCubes.nItems; } +Mvc_Cube_t * Mvc_CoverReadCubeHead( Mvc_Cover_t * pCover ) { return pCover->lCubes.pHead; } +Mvc_Cube_t * Mvc_CoverReadCubeTail( Mvc_Cover_t * pCover ) { return pCover->lCubes.pTail; } +Mvc_List_t * Mvc_CoverReadCubeList( Mvc_Cover_t * pCover ) { return &pCover->lCubes; } + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Mvc_ListReadCubeNum( Mvc_List_t * pList ) { return pList->nItems; } +Mvc_Cube_t * Mvc_ListReadCubeHead( Mvc_List_t * pList ) { return pList->pHead; } +Mvc_Cube_t * Mvc_ListReadCubeTail( Mvc_List_t * pList ) { return pList->pTail; } + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverSetCubeNum( Mvc_Cover_t * pCover,int nItems ) { pCover->lCubes.nItems = nItems; } +void Mvc_CoverSetCubeHead( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube ) { pCover->lCubes.pHead = pCube; } +void Mvc_CoverSetCubeTail( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube ) { pCover->lCubes.pTail = pCube; } +void Mvc_CoverSetCubeList( Mvc_Cover_t * pCover, Mvc_List_t * pList ) { pCover->lCubes = *pList; } + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Mvc_CoverIsEmpty( Mvc_Cover_t * pCover ) +{ + return Mvc_CoverReadCubeNum(pCover) == 0; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Mvc_CoverIsTautology( Mvc_Cover_t * pCover ) +{ + Mvc_Cube_t * pCube; + int iBit, Value; + + if ( Mvc_CoverReadCubeNum(pCover) != 1 ) + return 0; + + pCube = Mvc_CoverReadCubeHead( pCover ); + Mvc_CubeForEachBit( pCover, pCube, iBit, Value ) + if ( Value == 0 ) + return 0; + return 1; +} + +/**Function************************************************************* + + Synopsis [Returns 1 if the cover is a binary buffer.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Mvc_CoverIsBinaryBuffer( Mvc_Cover_t * pCover ) +{ + Mvc_Cube_t * pCube; + if ( pCover->nBits != 2 ) + return 0; + if ( Mvc_CoverReadCubeNum(pCover) != 1 ) + return 0; + pCube = pCover->lCubes.pHead; + if ( Mvc_CubeBitValue(pCube, 0) == 0 && Mvc_CubeBitValue(pCube, 1) == 1 ) + return 1; + return 0; +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverMakeEmpty( Mvc_Cover_t * pCover ) +{ + Mvc_Cube_t * pCube, * pCube2; + Mvc_CoverForEachCubeSafe( pCover, pCube, pCube2 ) + Mvc_CubeFree( pCover, pCube ); + pCover->lCubes.nItems = 0; + pCover->lCubes.pHead = NULL; + pCover->lCubes.pTail = NULL; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverMakeTautology( Mvc_Cover_t * pCover ) +{ + Mvc_Cube_t * pCubeNew; + Mvc_CoverMakeEmpty( pCover ); + pCubeNew = Mvc_CubeAlloc( pCover ); + Mvc_CubeBitFill( pCubeNew ); + Mvc_CoverAddCubeTail( pCover, pCubeNew ); +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Mvc_Cover_t * Mvc_CoverCreateEmpty( Mvc_Cover_t * pCover ) +{ + Mvc_Cover_t * pCoverNew; + pCoverNew = Mvc_CoverAlloc( pCover->pMem, pCover->nBits ); + return pCoverNew; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Mvc_Cover_t * Mvc_CoverCreateTautology( Mvc_Cover_t * pCover ) +{ + Mvc_Cube_t * pCubeNew; + Mvc_Cover_t * pCoverNew; + pCoverNew = Mvc_CoverAlloc( pCover->pMem, pCover->nBits ); + pCubeNew = Mvc_CubeAlloc( pCoverNew ); + Mvc_CubeBitFill( pCubeNew ); + Mvc_CoverAddCubeTail( pCoverNew, pCubeNew ); + return pCoverNew; +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/misc/mvc/mvcCompare.c b/src/misc/mvc/mvcCompare.c new file mode 100644 index 00000000..9cff99cd --- /dev/null +++ b/src/misc/mvc/mvcCompare.c @@ -0,0 +1,369 @@ +/**CFile**************************************************************** + + FileName [mvcCompare.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [Various cube comparison functions.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: mvcCompare.c,v 1.5 2003/04/03 23:25:41 alanmi Exp $] + +***********************************************************************/ + +#include "mvc.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Compares two cubes according to their integer value.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Mvc_CubeCompareInt( Mvc_Cube_t * pC1, Mvc_Cube_t * pC2, Mvc_Cube_t * pMask ) +{ + if ( Mvc_Cube1Words(pC1) ) + { + if ( pC1->pData[0] < pC2->pData[0] ) + return -1; + if ( pC1->pData[0] > pC2->pData[0] ) + return 1; + return 0; + } + else if ( Mvc_Cube2Words(pC1) ) + { + if ( pC1->pData[1] < pC2->pData[1] ) + return -1; + if ( pC1->pData[1] > pC2->pData[1] ) + return 1; + if ( pC1->pData[0] < pC2->pData[0] ) + return -1; + if ( pC1->pData[0] > pC2->pData[0] ) + return 1; + return 0; + } + else + { + int i = Mvc_CubeReadLast(pC1); + for(; i >= 0; i--) + { + if ( pC1->pData[i] < pC2->pData[i] ) + return -1; + if ( pC1->pData[i] > pC2->pData[i] ) + return 1; + } + return 0; + } +} + + +/**Function************************************************************* + + Synopsis [Compares the cubes (1) by size, (2) by integer value.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Mvc_CubeCompareSizeAndInt( Mvc_Cube_t * pC1, Mvc_Cube_t * pC2, Mvc_Cube_t * pMask ) +{ + // compare the cubes by size + if ( Mvc_CubeReadSize( pC1 ) < Mvc_CubeReadSize( pC2 ) ) + return 1; + if ( Mvc_CubeReadSize( pC1 ) > Mvc_CubeReadSize( pC2 ) ) + return -1; + // the cubes have the same size + + // compare the cubes as integers + if ( Mvc_Cube1Words( pC1 ) ) + { + if ( pC1->pData[0] < pC2->pData[0] ) + return -1; + if ( pC1->pData[0] > pC2->pData[0] ) + return 1; + return 0; + } + else if ( Mvc_Cube2Words( pC1 ) ) + { + if ( pC1->pData[1] < pC2->pData[1] ) + return -1; + if ( pC1->pData[1] > pC2->pData[1] ) + return 1; + if ( pC1->pData[0] < pC2->pData[0] ) + return -1; + if ( pC1->pData[0] > pC2->pData[0] ) + return 1; + return 0; + } + else + { + int i = Mvc_CubeReadLast( pC1 ); + for(; i >= 0; i--) + { + if ( pC1->pData[i] < pC2->pData[i] ) + return -1; + if ( pC1->pData[i] > pC2->pData[i] ) + return 1; + } + return 0; + } +} + +/**Function************************************************************* + + Synopsis [Compares two cubes under the mask.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Mvc_CubeCompareIntUnderMask( Mvc_Cube_t * pC1, Mvc_Cube_t * pC2, Mvc_Cube_t * pMask ) +{ + unsigned uBits1, uBits2; + + // compare the cubes under the mask + if ( Mvc_Cube1Words(pC1) ) + { + uBits1 = pC1->pData[0] & pMask->pData[0]; + uBits2 = pC2->pData[0] & pMask->pData[0]; + if ( uBits1 < uBits2 ) + return -1; + if ( uBits1 > uBits2 ) + return 1; + // cubes are equal + return 0; + } + else if ( Mvc_Cube2Words(pC1) ) + { + uBits1 = pC1->pData[1] & pMask->pData[1]; + uBits2 = pC2->pData[1] & pMask->pData[1]; + if ( uBits1 < uBits2 ) + return -1; + if ( uBits1 > uBits2 ) + return 1; + uBits1 = pC1->pData[0] & pMask->pData[0]; + uBits2 = pC2->pData[0] & pMask->pData[0]; + if ( uBits1 < uBits2 ) + return -1; + if ( uBits1 > uBits2 ) + return 1; + return 0; + } + else + { + int i = Mvc_CubeReadLast(pC1); + for(; i >= 0; i--) + { + uBits1 = pC1->pData[i] & pMask->pData[i]; + uBits2 = pC2->pData[i] & pMask->pData[i]; + if ( uBits1 < uBits2 ) + return -1; + if ( uBits1 > uBits2 ) + return 1; + } + return 0; + } +} + +/**Function************************************************************* + + Synopsis [Compares two cubes under the mask.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Mvc_CubeCompareIntOutsideMask( Mvc_Cube_t * pC1, Mvc_Cube_t * pC2, Mvc_Cube_t * pMask ) +{ + unsigned uBits1, uBits2; + + // compare the cubes under the mask + if ( Mvc_Cube1Words(pC1) ) + { + uBits1 = pC1->pData[0] | pMask->pData[0]; + uBits2 = pC2->pData[0] | pMask->pData[0]; + if ( uBits1 < uBits2 ) + return -1; + if ( uBits1 > uBits2 ) + return 1; + // cubes are equal + return 0; + } + else if ( Mvc_Cube2Words(pC1) ) + { + uBits1 = pC1->pData[1] | pMask->pData[1]; + uBits2 = pC2->pData[1] | pMask->pData[1]; + if ( uBits1 < uBits2 ) + return -1; + if ( uBits1 > uBits2 ) + return 1; + uBits1 = pC1->pData[0] | pMask->pData[0]; + uBits2 = pC2->pData[0] | pMask->pData[0]; + if ( uBits1 < uBits2 ) + return -1; + if ( uBits1 > uBits2 ) + return 1; + return 0; + } + else + { + int i = Mvc_CubeReadLast(pC1); + for(; i >= 0; i--) + { + uBits1 = pC1->pData[i] | pMask->pData[i]; + uBits2 = pC2->pData[i] | pMask->pData[i]; + if ( uBits1 < uBits2 ) + return -1; + if ( uBits1 > uBits2 ) + return 1; + } + return 0; + } +} + + +/**Function************************************************************* + + Synopsis [Compares the cubes (1) outside the mask, (2) under the mask.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Mvc_CubeCompareIntOutsideAndUnderMask( Mvc_Cube_t * pC1, Mvc_Cube_t * pC2, Mvc_Cube_t * pMask ) +{ + unsigned uBits1, uBits2; + + if ( Mvc_Cube1Words(pC1) ) + { + // compare the cubes outside the mask + uBits1 = pC1->pData[0] & ~(pMask->pData[0]); + uBits2 = pC2->pData[0] & ~(pMask->pData[0]); + if ( uBits1 < uBits2 ) + return -1; + if ( uBits1 > uBits2 ) + return 1; + + // compare the cubes under the mask + uBits1 = pC1->pData[0] & pMask->pData[0]; + uBits2 = pC2->pData[0] & pMask->pData[0]; + if ( uBits1 < uBits2 ) + return -1; + if ( uBits1 > uBits2 ) + return 1; + // cubes are equal + // should never happen + assert( 0 ); + return 0; + } + else if ( Mvc_Cube2Words(pC1) ) + { + // compare the cubes outside the mask + uBits1 = pC1->pData[1] & ~(pMask->pData[1]); + uBits2 = pC2->pData[1] & ~(pMask->pData[1]); + if ( uBits1 < uBits2 ) + return -1; + if ( uBits1 > uBits2 ) + return 1; + + uBits1 = pC1->pData[0] & ~(pMask->pData[0]); + uBits2 = pC2->pData[0] & ~(pMask->pData[0]); + if ( uBits1 < uBits2 ) + return -1; + if ( uBits1 > uBits2 ) + return 1; + + // compare the cubes under the mask + uBits1 = pC1->pData[1] & pMask->pData[1]; + uBits2 = pC2->pData[1] & pMask->pData[1]; + if ( uBits1 < uBits2 ) + return -1; + if ( uBits1 > uBits2 ) + return 1; + + uBits1 = pC1->pData[0] & pMask->pData[0]; + uBits2 = pC2->pData[0] & pMask->pData[0]; + if ( uBits1 < uBits2 ) + return -1; + if ( uBits1 > uBits2 ) + return 1; + + // cubes are equal + // should never happen + assert( 0 ); + return 0; + } + else + { + int i; + + // compare the cubes outside the mask + for( i = Mvc_CubeReadLast(pC1); i >= 0; i-- ) + { + uBits1 = pC1->pData[i] & ~(pMask->pData[i]); + uBits2 = pC2->pData[i] & ~(pMask->pData[i]); + if ( uBits1 < uBits2 ) + return -1; + if ( uBits1 > uBits2 ) + return 1; + } + // compare the cubes under the mask + for( i = Mvc_CubeReadLast(pC1); i >= 0; i-- ) + { + uBits1 = pC1->pData[i] & pMask->pData[i]; + uBits2 = pC2->pData[i] & pMask->pData[i]; + if ( uBits1 < uBits2 ) + return -1; + if ( uBits1 > uBits2 ) + return 1; + } +/* + { + Mvc_Cover_t * pCover; + pCover = Mvc_CoverAlloc( NULL, 96 ); + Mvc_CubePrint( pCover, pC1 ); + Mvc_CubePrint( pCover, pC2 ); + Mvc_CubePrint( pCover, pMask ); + } +*/ + // cubes are equal + // should never happen + assert( 0 ); + return 0; + } +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/misc/mvc/mvcContain.c b/src/misc/mvc/mvcContain.c new file mode 100644 index 00000000..a9eae06e --- /dev/null +++ b/src/misc/mvc/mvcContain.c @@ -0,0 +1,173 @@ +/**CFile**************************************************************** + + FileName [mvcContain.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [Making the cover single-cube containment free.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: mvcContain.c,v 1.4 2003/04/03 23:25:42 alanmi Exp $] + +***********************************************************************/ + +#include "mvc.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static void Mvc_CoverRemoveDuplicates( Mvc_Cover_t * pCover ); +static void Mvc_CoverRemoveContained( Mvc_Cover_t * pCover ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + + +/**Function************************************************************* + + Synopsis [Removes the contained cubes.] + + Description [Returns 1 if the cover has been changed.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Mvc_CoverContain( Mvc_Cover_t * pCover ) +{ + int nCubes; + nCubes = Mvc_CoverReadCubeNum( pCover ); + if ( nCubes < 2 ) + return 0; + Mvc_CoverSetCubeSizes(pCover); + Mvc_CoverSort( pCover, NULL, Mvc_CubeCompareSizeAndInt ); + Mvc_CoverRemoveDuplicates( pCover ); + if ( nCubes > 1 ) + Mvc_CoverRemoveContained( pCover ); + return (nCubes != Mvc_CoverReadCubeNum(pCover)); +} + +/**Function************************************************************* + + Synopsis [Removes adjacent duplicated cubes from the cube list.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverRemoveDuplicates( Mvc_Cover_t * pCover ) +{ + Mvc_Cube_t * pPrev, * pCube, * pCube2; + int fEqual; + + // set the first cube of the cover + pPrev = Mvc_CoverReadCubeHead(pCover); + // go through all the cubes after this one + Mvc_CoverForEachCubeStartSafe( Mvc_CubeReadNext(pPrev), pCube, pCube2 ) + { + // compare the current cube with the prev cube + Mvc_CubeBitEqual( fEqual, pPrev, pCube ); + if ( fEqual ) + { // they are equal - remove the current cube + Mvc_CoverDeleteCube( pCover, pPrev, pCube ); + Mvc_CubeFree( pCover, pCube ); + // don't change the previous cube cube + } + else + { // they are not equal - update the previous cube + pPrev = pCube; + } + } +} + +/**Function************************************************************* + + Synopsis [Removes contained cubes from the sorted cube list.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverRemoveContained( Mvc_Cover_t * pCover ) +{ + Mvc_Cube_t * pCubeBeg, * pCubeEnd, * pCubeLarge; + Mvc_Cube_t * pCube, * pCube2, * pPrev; + unsigned sizeCur; + int Result; + + // since the cubes are sorted by size, it is sufficient + // to compare each cube with other cubes that have larger sizes + // if the given cube implies a larger cube, the larger cube is removed + pCubeBeg = Mvc_CoverReadCubeHead(pCover); + do + { + // get the current cube size + sizeCur = Mvc_CubeReadSize(pCubeBeg); + + // initialize the end of the given size group + pCubeEnd = pCubeBeg; + // find the beginning of the next size group + Mvc_CoverForEachCubeStart( Mvc_CubeReadNext(pCubeBeg), pCube ) + { + if ( sizeCur == Mvc_CubeReadSize(pCube) ) + pCubeEnd = pCube; + else // pCube is the first cube in the new size group + break; + } + // if we could not find the next size group + // the containment check is finished + if ( pCube == NULL ) + break; + // otherwise, pCubeBeg/pCubeEnd are the first/last cubes of the group + + // go through all the cubes between pCubeBeg and pCubeEnd, inclusive, + // and for each of them, try removing cubes after pCubeEnd + Mvc_CoverForEachCubeStart( pCubeBeg, pCubeLarge ) + { + pPrev = pCubeEnd; + Mvc_CoverForEachCubeStartSafe( Mvc_CubeReadNext(pCubeEnd), pCube, pCube2 ) + { + // check containment + Mvc_CubeBitNotImpl( Result, pCube, pCubeLarge ); + if ( !Result ) + { // pCubeLarge implies pCube - remove pCube + Mvc_CoverDeleteCube( pCover, pPrev, pCube ); + Mvc_CubeFree( pCover, pCube ); + // don't update the previous cube + } + else + { // update the previous cube + pPrev = pCube; + } + } + // quit, if the main cube was the last one of this size + if ( pCubeLarge == pCubeEnd ) + break; + } + + // set the beginning of the next group + pCubeBeg = Mvc_CubeReadNext(pCubeEnd); + } + while ( pCubeBeg ); +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/misc/mvc/mvcCover.c b/src/misc/mvc/mvcCover.c new file mode 100644 index 00000000..d8584446 --- /dev/null +++ b/src/misc/mvc/mvcCover.c @@ -0,0 +1,251 @@ +/**CFile**************************************************************** + + FileName [mvcCover.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [Basic procedures to manipulate unate cube covers.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: mvcCover.c,v 1.5 2003/04/09 18:02:05 alanmi Exp $] + +***********************************************************************/ + +#include "mvc.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Mvc_Cover_t * Mvc_CoverAlloc( Mvc_Manager_t * pMem, int nBits ) +{ + Mvc_Cover_t * p; + int nBitsInUnsigned; + + nBitsInUnsigned = 8 * sizeof(Mvc_CubeWord_t); +#ifdef USE_SYSTEM_MEMORY_MANAGEMENT + p = (Mvc_Cover_t *)malloc( sizeof(Mvc_Cover_t) ); +#else + p = (Mvc_Cover_t *)Extra_MmFixedEntryFetch( pMem->pManC ); +#endif + p->pMem = pMem; + p->nBits = nBits; + p->nWords = nBits / nBitsInUnsigned + (int)(nBits % nBitsInUnsigned > 0); + p->nUnused = p->nWords * nBitsInUnsigned - p->nBits; + p->lCubes.nItems = 0; + p->lCubes.pHead = NULL; + p->lCubes.pTail = NULL; + p->nCubesAlloc = 0; + p->pCubes = NULL; + p->pMask = NULL; + p->pLits = NULL; + return p; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Mvc_Cover_t * Mvc_CoverClone( Mvc_Cover_t * p ) +{ + Mvc_Cover_t * pCover; +#ifdef USE_SYSTEM_MEMORY_MANAGEMENT + pCover = (Mvc_Cover_t *)malloc( sizeof(Mvc_Cover_t) ); +#else + pCover = (Mvc_Cover_t *)Extra_MmFixedEntryFetch( p->pMem->pManC ); +#endif + pCover->pMem = p->pMem; + pCover->nBits = p->nBits; + pCover->nWords = p->nWords; + pCover->nUnused = p->nUnused; + pCover->lCubes.nItems = 0; + pCover->lCubes.pHead = NULL; + pCover->lCubes.pTail = NULL; + pCover->nCubesAlloc = 0; + pCover->pCubes = NULL; + pCover->pMask = NULL; + pCover->pLits = NULL; + return pCover; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Mvc_Cover_t * Mvc_CoverDup( Mvc_Cover_t * p ) +{ + Mvc_Cover_t * pCover; + Mvc_Cube_t * pCube, * pCubeCopy; + // clone the cover + pCover = Mvc_CoverClone( p ); + // copy the cube list + Mvc_CoverForEachCube( p, pCube ) + { + pCubeCopy = Mvc_CubeDup( p, pCube ); + Mvc_CoverAddCubeTail( pCover, pCubeCopy ); + } + return pCover; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverFree( Mvc_Cover_t * p ) +{ + Mvc_Cube_t * pCube, * pCube2; + // recycle cube list + Mvc_CoverForEachCubeSafe( p, pCube, pCube2 ) + Mvc_CubeFree( p, pCube ); + // recycle other pointers + Mvc_CubeFree( p, p->pMask ); + MEM_FREE( p->pMem, Mvc_Cube_t *, p->nCubesAlloc, p->pCubes ); + MEM_FREE( p->pMem, int, p->nBits, p->pLits ); + +#ifdef USE_SYSTEM_MEMORY_MANAGEMENT + free( p ); +#else + Extra_MmFixedEntryRecycle( p->pMem->pManC, (char *)p ); +#endif +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverAllocateMask( Mvc_Cover_t * pCover ) +{ + if ( pCover->pMask == NULL ) + pCover->pMask = Mvc_CubeAlloc( pCover ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverAllocateArrayLits( Mvc_Cover_t * pCover ) +{ + if ( pCover->pLits == NULL ) + pCover->pLits = MEM_ALLOC( pCover->pMem, int, pCover->nBits ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverAllocateArrayCubes( Mvc_Cover_t * pCover ) +{ + if ( pCover->nCubesAlloc < pCover->lCubes.nItems ) + { + if ( pCover->nCubesAlloc > 0 ) + MEM_FREE( pCover->pMem, Mvc_Cube_t *, pCover->nCubesAlloc, pCover->pCubes ); + pCover->nCubesAlloc = pCover->lCubes.nItems; + pCover->pCubes = MEM_ALLOC( pCover->pMem, Mvc_Cube_t *, pCover->nCubesAlloc ); + } +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverDeallocateMask( Mvc_Cover_t * pCover ) +{ + Mvc_CubeFree( pCover, pCover->pMask ); + pCover->pMask = NULL; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverDeallocateArrayLits( Mvc_Cover_t * pCover ) +{ + if ( pCover->pLits ) + { + MEM_FREE( pCover->pMem, int, pCover->nBits, pCover->pLits ); + pCover->pLits = NULL; + } +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/misc/mvc/mvcCube.c b/src/misc/mvc/mvcCube.c new file mode 100644 index 00000000..e157879f --- /dev/null +++ b/src/misc/mvc/mvcCube.c @@ -0,0 +1,175 @@ +/**CFile**************************************************************** + + FileName [mvcCube.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [Manipulating unate cubes.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: mvcCube.c,v 1.4 2003/04/03 06:31:49 alanmi Exp $] + +***********************************************************************/ + +#include "mvc.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Mvc_Cube_t * Mvc_CubeAlloc( Mvc_Cover_t * pCover ) +{ + Mvc_Cube_t * pCube; + + assert( pCover->nWords >= 0 ); + // allocate the cube +#ifdef USE_SYSTEM_MEMORY_MANAGEMENT + if ( pCover->nWords == 0 ) + pCube = (Mvc_Cube_t *)malloc( sizeof(Mvc_Cube_t) ); + else + pCube = (Mvc_Cube_t *)malloc( sizeof(Mvc_Cube_t) + sizeof(Mvc_CubeWord_t) * (pCover->nWords - 1) ); +#else + switch( pCover->nWords ) + { + case 0: + case 1: + pCube = (Mvc_Cube_t *)Extra_MmFixedEntryFetch( pCover->pMem->pMan1 ); + break; + case 2: + pCube = (Mvc_Cube_t *)Extra_MmFixedEntryFetch( pCover->pMem->pMan2 ); + break; + case 3: + case 4: + pCube = (Mvc_Cube_t *)Extra_MmFixedEntryFetch( pCover->pMem->pMan4 ); + break; + default: + pCube = (Mvc_Cube_t *)malloc( sizeof(Mvc_Cube_t) + sizeof(Mvc_CubeWord_t) * (pCover->nWords - 1) ); + break; + } +#endif + // set the parameters charactering this cube + if ( pCover->nWords == 0 ) + pCube->iLast = pCover->nWords; + else + pCube->iLast = pCover->nWords - 1; + pCube->nUnused = pCover->nUnused; + return pCube; +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Mvc_Cube_t * Mvc_CubeDup( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube ) +{ + Mvc_Cube_t * pCubeCopy; + pCubeCopy = Mvc_CubeAlloc( pCover ); + Mvc_CubeBitCopy( pCubeCopy, pCube ); + return pCubeCopy; +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CubeFree( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube ) +{ + if ( pCube == NULL ) + return; + + // verify the parameters charactering this cube + assert( pCube->iLast == 0 || ((int)pCube->iLast) == pCover->nWords - 1 ); + assert( ((int)pCube->nUnused) == pCover->nUnused ); + + // deallocate the cube +#ifdef USE_SYSTEM_MEMORY_MANAGEMENT + free( pCube ); +#else + switch( pCover->nWords ) + { + case 0: + case 1: + Extra_MmFixedEntryRecycle( pCover->pMem->pMan1, (char *)pCube ); + break; + case 2: + Extra_MmFixedEntryRecycle( pCover->pMem->pMan2, (char *)pCube ); + break; + case 3: + case 4: + Extra_MmFixedEntryRecycle( pCover->pMem->pMan4, (char *)pCube ); + break; + default: + free( pCube ); + break; + } +#endif +} + + +/**Function************************************************************* + + Synopsis [Removes the don't-care variable from the cube.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CubeBitRemoveDcs( Mvc_Cube_t * pCube ) +{ + unsigned Mask; + int i; + for ( i = Mvc_CubeReadLast(pCube); i >= 0; i-- ) + { + // detect those variables that are different (not DCs) + Mask = (pCube->pData[i] ^ (pCube->pData[i] >> 1)) & BITS_DISJOINT; + // create the mask of all that are different + Mask |= (Mask << 1); + // remove other bits from the set + pCube->pData[i] &= Mask; + } +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/misc/mvc/mvcDivide.c b/src/misc/mvc/mvcDivide.c new file mode 100644 index 00000000..03643dcf --- /dev/null +++ b/src/misc/mvc/mvcDivide.c @@ -0,0 +1,436 @@ +/**CFile**************************************************************** + + FileName [mvcDivide.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [Procedures for algebraic division.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: mvcDivide.c,v 1.5 2003/04/26 20:41:36 alanmi Exp $] + +***********************************************************************/ + +#include "mvc.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static void Mvc_CoverVerifyDivision( Mvc_Cover_t * pCover, Mvc_Cover_t * pDiv, Mvc_Cover_t * pQuo, Mvc_Cover_t * pRem ); + +int s_fVerbose = 0; + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverDivide( Mvc_Cover_t * pCover, Mvc_Cover_t * pDiv, Mvc_Cover_t ** ppQuo, Mvc_Cover_t ** ppRem ) +{ + // check the number of cubes + if ( Mvc_CoverReadCubeNum( pCover ) < Mvc_CoverReadCubeNum( pDiv ) ) + { + *ppQuo = NULL; + *ppRem = NULL; + return; + } + + // make sure that support of pCover contains that of pDiv + if ( !Mvc_CoverCheckSuppContainment( pCover, pDiv ) ) + { + *ppQuo = NULL; + *ppRem = NULL; + return; + } + + // perform the general division + Mvc_CoverDivideInternal( pCover, pDiv, ppQuo, ppRem ); +} + + +/**Function************************************************************* + + Synopsis [Merge the cubes inside the groups.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverDivideInternal( Mvc_Cover_t * pCover, Mvc_Cover_t * pDiv, Mvc_Cover_t ** ppQuo, Mvc_Cover_t ** ppRem ) +{ + Mvc_Cover_t * pQuo, * pRem; + Mvc_Cube_t * pCubeC, * pCubeD, * pCubeCopy; + Mvc_Cube_t * pCube1, * pCube2; + int * pGroups, nGroups; // the cube groups + int nCubesC, nCubesD, nMerges, iCubeC, iCubeD, iMerge; + int fSkipG, GroupSize, g, c, RetValue; + int nCubes; + + // get cover sizes + nCubesD = Mvc_CoverReadCubeNum( pDiv ); + nCubesC = Mvc_CoverReadCubeNum( pCover ); + + // check trivial cases + if ( nCubesD == 1 ) + { + if ( Mvc_CoverIsOneLiteral( pDiv ) ) + Mvc_CoverDivideByLiteral( pCover, pDiv, ppQuo, ppRem ); + else + Mvc_CoverDivideByCube( pCover, pDiv, ppQuo, ppRem ); + return; + } + + // create the divisor and the remainder + pQuo = Mvc_CoverAlloc( pCover->pMem, pCover->nBits ); + pRem = Mvc_CoverAlloc( pCover->pMem, pCover->nBits ); + + // get the support of the divisor + Mvc_CoverAllocateMask( pDiv ); + Mvc_CoverSupport( pDiv, pDiv->pMask ); + + // sort the cubes of the divisor + Mvc_CoverSort( pDiv, NULL, Mvc_CubeCompareInt ); + // sort the cubes of the cover + Mvc_CoverSort( pCover, pDiv->pMask, Mvc_CubeCompareIntOutsideAndUnderMask ); + + // allocate storage for cube groups + pGroups = MEM_ALLOC( pCover->pMem, int, nCubesC + 1 ); + + // mask contains variables in the support of Div + // split the cubes into groups using the mask + Mvc_CoverList2Array( pCover ); + Mvc_CoverList2Array( pDiv ); + pGroups[0] = 0; + nGroups = 1; + for ( c = 1; c < nCubesC; c++ ) + { + // get the cubes + pCube1 = pCover->pCubes[c-1]; + pCube2 = pCover->pCubes[c ]; + // compare the cubes + Mvc_CubeBitEqualOutsideMask( RetValue, pCube1, pCube2, pDiv->pMask ); + if ( !RetValue ) + pGroups[nGroups++] = c; + } + // finish off the last group + pGroups[nGroups] = nCubesC; + + // consider each group separately and decide + // whether it can produce a quotient cube + nCubes = 0; + for ( g = 0; g < nGroups; g++ ) + { + // if the group has less than nCubesD cubes, + // there is no way it can produce the quotient cube + // copy the cubes to the remainder + GroupSize = pGroups[g+1] - pGroups[g]; + if ( GroupSize < nCubesD ) + { + for ( c = pGroups[g]; c < pGroups[g+1]; c++ ) + { + pCubeCopy = Mvc_CubeDup( pRem, pCover->pCubes[c] ); + Mvc_CoverAddCubeTail( pRem, pCubeCopy ); + nCubes++; + } + continue; + } + + // mark the cubes as those that should be added to the remainder + for ( c = pGroups[g]; c < pGroups[g+1]; c++ ) + Mvc_CubeSetSize( pCover->pCubes[c], 1 ); + + // go through the cubes in the group and at the same time + // go through the cubes in the divisor + iCubeD = 0; + iCubeC = 0; + pCubeD = pDiv->pCubes[iCubeD++]; + pCubeC = pCover->pCubes[pGroups[g]+iCubeC++]; + fSkipG = 0; + nMerges = 0; + + while ( 1 ) + { + // compare the topmost cubes in F and in D + RetValue = Mvc_CubeCompareIntUnderMask( pCubeC, pCubeD, pDiv->pMask ); + // cube are ordered in increasing order of their int value + if ( RetValue == -1 ) // pCubeC is above pCubeD + { // cube in C should be added to the remainder + // check that there is enough cubes in the group + if ( GroupSize - iCubeC < nCubesD - nMerges ) + { + fSkipG = 1; + break; + } + // get the next cube in the cover + pCubeC = pCover->pCubes[pGroups[g]+iCubeC++]; + continue; + } + if ( RetValue == 1 ) // pCubeD is above pCubeC + { // given cube in D does not have a corresponding cube in the cover + fSkipG = 1; + break; + } + // mark the cube as the one that should NOT be added to the remainder + Mvc_CubeSetSize( pCubeC, 0 ); + // remember this merged cube + iMerge = iCubeC-1; + nMerges++; + + // stop if we considered the last cube of the group + if ( iCubeD == nCubesD ) + break; + + // advance the cube of the divisor + assert( iCubeD < nCubesD ); + pCubeD = pDiv->pCubes[iCubeD++]; + + // advance the cube of the group + assert( pGroups[g]+iCubeC < nCubesC ); + pCubeC = pCover->pCubes[pGroups[g]+iCubeC++]; + } + + if ( fSkipG ) + { + // the group has failed, add all the cubes to the remainder + for ( c = pGroups[g]; c < pGroups[g+1]; c++ ) + { + pCubeCopy = Mvc_CubeDup( pRem, pCover->pCubes[c] ); + Mvc_CoverAddCubeTail( pRem, pCubeCopy ); + nCubes++; + } + continue; + } + + // the group has worked, add left-over cubes to the remainder + for ( c = pGroups[g]; c < pGroups[g+1]; c++ ) + { + pCubeC = pCover->pCubes[c]; + if ( Mvc_CubeReadSize(pCubeC) ) + { + pCubeCopy = Mvc_CubeDup( pRem, pCubeC ); + Mvc_CoverAddCubeTail( pRem, pCubeCopy ); + nCubes++; + } + } + + // create the quotient cube + pCube1 = Mvc_CubeAlloc( pQuo ); + Mvc_CubeBitSharp( pCube1, pCover->pCubes[pGroups[g]+iMerge], pDiv->pMask ); + // add the cube to the quotient + Mvc_CoverAddCubeTail( pQuo, pCube1 ); + nCubes += nCubesD; + } + assert( nCubes == nCubesC ); + + // deallocate the memory + MEM_FREE( pCover->pMem, int, nCubesC + 1, pGroups ); + + // return the results + *ppRem = pRem; + *ppQuo = pQuo; +// Mvc_CoverVerifyDivision( pCover, pDiv, pQuo, pRem ); +} + + +/**Function************************************************************* + + Synopsis [Divides the cover by a cube.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverDivideByCube( Mvc_Cover_t * pCover, Mvc_Cover_t * pDiv, Mvc_Cover_t ** ppQuo, Mvc_Cover_t ** ppRem ) +{ + Mvc_Cover_t * pQuo, * pRem; + Mvc_Cube_t * pCubeC, * pCubeD, * pCubeCopy; + int CompResult; + + // get the only cube of D + assert( Mvc_CoverReadCubeNum(pDiv) == 1 ); + + // start the quotient and the remainder + pQuo = Mvc_CoverAlloc( pCover->pMem, pCover->nBits ); + pRem = Mvc_CoverAlloc( pCover->pMem, pCover->nBits ); + + // get the first and only cube of the divisor + pCubeD = Mvc_CoverReadCubeHead( pDiv ); + + // iterate through the cubes in the cover + Mvc_CoverForEachCube( pCover, pCubeC ) + { + // check the containment of literals from pCubeD in pCube + Mvc_Cube2BitNotImpl( CompResult, pCubeD, pCubeC ); + if ( !CompResult ) + { // this cube belongs to the quotient + // alloc the cube + pCubeCopy = Mvc_CubeAlloc( pQuo ); + // clean the support of D + Mvc_CubeBitSharp( pCubeCopy, pCubeC, pCubeD ); + // add the cube to the quotient + Mvc_CoverAddCubeTail( pQuo, pCubeCopy ); + } + else + { + // copy the cube + pCubeCopy = Mvc_CubeDup( pRem, pCubeC ); + // add the cube to the remainder + Mvc_CoverAddCubeTail( pRem, pCubeCopy ); + } + } + // return the results + *ppRem = pRem; + *ppQuo = pQuo; +} + +/**Function************************************************************* + + Synopsis [Divides the cover by a literal.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverDivideByLiteral( Mvc_Cover_t * pCover, Mvc_Cover_t * pDiv, Mvc_Cover_t ** ppQuo, Mvc_Cover_t ** ppRem ) +{ + Mvc_Cover_t * pQuo, * pRem; + Mvc_Cube_t * pCubeC, * pCubeCopy; + int iLit; + + // get the only cube of D + assert( Mvc_CoverReadCubeNum(pDiv) == 1 ); + + // start the quotient and the remainder + pQuo = Mvc_CoverAlloc( pCover->pMem, pCover->nBits ); + pRem = Mvc_CoverAlloc( pCover->pMem, pCover->nBits ); + + // get the first and only literal in the divisor cube + iLit = Mvc_CoverFirstCubeFirstLit( pDiv ); + + // iterate through the cubes in the cover + Mvc_CoverForEachCube( pCover, pCubeC ) + { + // copy the cube + pCubeCopy = Mvc_CubeDup( pCover, pCubeC ); + // add the cube to the quotient or to the remainder depending on the literal + if ( Mvc_CubeBitValue( pCubeCopy, iLit ) ) + { // remove the literal + Mvc_CubeBitRemove( pCubeCopy, iLit ); + // add the cube ot the quotient + Mvc_CoverAddCubeTail( pQuo, pCubeCopy ); + } + else + { // add the cube ot the remainder + Mvc_CoverAddCubeTail( pRem, pCubeCopy ); + } + } + // return the results + *ppRem = pRem; + *ppQuo = pQuo; +} + + +/**Function************************************************************* + + Synopsis [Derives the quotient of division by literal.] + + Description [Reduces the cover to be the equal to the result of + division of the given cover by the literal.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverDivideByLiteralQuo( Mvc_Cover_t * pCover, int iLit ) +{ + Mvc_Cube_t * pCube, * pCube2, * pPrev; + // delete those cubes that do not have this literal + // remove this literal from other cubes + pPrev = NULL; + Mvc_CoverForEachCubeSafe( pCover, pCube, pCube2 ) + { + if ( Mvc_CubeBitValue( pCube, iLit ) == 0 ) + { // delete the cube from the cover + Mvc_CoverDeleteCube( pCover, pPrev, pCube ); + Mvc_CubeFree( pCover, pCube ); + // don't update the previous cube + } + else + { // delete this literal from the cube + Mvc_CubeBitRemove( pCube, iLit ); + // update the previous cube + pPrev = pCube; + } + } +} + + +/**Function************************************************************* + + Synopsis [Verifies that the result of algebraic division is correct.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverVerifyDivision( Mvc_Cover_t * pCover, Mvc_Cover_t * pDiv, Mvc_Cover_t * pQuo, Mvc_Cover_t * pRem ) +{ + Mvc_Cover_t * pProd; + Mvc_Cover_t * pDiff; + + pProd = Mvc_CoverAlgebraicMultiply( pDiv, pQuo ); + pDiff = Mvc_CoverAlgebraicSubtract( pCover, pProd ); + + if ( Mvc_CoverAlgebraicEqual( pDiff, pRem ) ) + printf( "Verification OKAY!\n" ); + else + { + printf( "Verification FAILED!\n" ); + printf( "pCover:\n" ); + Mvc_CoverPrint( pCover ); + printf( "pDiv:\n" ); + Mvc_CoverPrint( pDiv ); + printf( "pRem:\n" ); + Mvc_CoverPrint( pRem ); + printf( "pQuo:\n" ); + Mvc_CoverPrint( pQuo ); + } + + Mvc_CoverFree( pProd ); + Mvc_CoverFree( pDiff ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/misc/mvc/mvcDivisor.c b/src/misc/mvc/mvcDivisor.c new file mode 100644 index 00000000..ecdea75b --- /dev/null +++ b/src/misc/mvc/mvcDivisor.c @@ -0,0 +1,90 @@ +/**CFile**************************************************************** + + FileName [mvcDivisor.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [Procedures for compute the quick divisor.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: mvcDivisor.c,v 1.1 2003/04/03 15:34:08 alanmi Exp $] + +***********************************************************************/ + +#include "mvc.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static void Mvc_CoverDivisorZeroKernel( Mvc_Cover_t * pCover ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Returns the quick divisor of the cover.] + + Description [Returns NULL, if there is not divisor other than + trivial.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Mvc_Cover_t * Mvc_CoverDivisor( Mvc_Cover_t * pCover ) +{ + Mvc_Cover_t * pKernel; + if ( Mvc_CoverReadCubeNum(pCover) <= 1 ) + return NULL; + // allocate the literal array and count literals + if ( Mvc_CoverAnyLiteral( pCover, NULL ) == -1 ) + return NULL; + // duplicate the cover + pKernel = Mvc_CoverDup(pCover); + // perform the kerneling + Mvc_CoverDivisorZeroKernel( pKernel ); + assert( Mvc_CoverReadCubeNum(pKernel) ); + return pKernel; +} + +/**Function************************************************************* + + Synopsis [Computes a level-zero kernel.] + + Description [Modifies the cover to contain one level-zero kernel.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverDivisorZeroKernel( Mvc_Cover_t * pCover ) +{ + int iLit; + // find any literal that occurs at least two times +// iLit = Mvc_CoverAnyLiteral( pCover, NULL ); + iLit = Mvc_CoverWorstLiteral( pCover, NULL ); +// iLit = Mvc_CoverBestLiteral( pCover, NULL ); + if ( iLit == -1 ) + return; + // derive the cube-free quotient + Mvc_CoverDivideByLiteralQuo( pCover, iLit ); // the same cover + Mvc_CoverMakeCubeFree( pCover ); // the same cover + // call recursively + Mvc_CoverDivisorZeroKernel( pCover ); // the same cover +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/misc/mvc/mvcList.c b/src/misc/mvc/mvcList.c new file mode 100644 index 00000000..8a82f911 --- /dev/null +++ b/src/misc/mvc/mvcList.c @@ -0,0 +1,362 @@ +/**CFile**************************************************************** + + FileName [mvcList.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [Manipulating list of cubes in the cover.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: mvcList.c,v 1.4 2003/04/03 06:31:50 alanmi Exp $] + +***********************************************************************/ + +#include "mvc.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_ListAddCubeHead_( Mvc_List_t * pList, Mvc_Cube_t * pCube ) +{ + if ( pList->pHead == NULL ) + { + Mvc_CubeSetNext( pCube, NULL ); + pList->pHead = pCube; + pList->pTail = pCube; + } + else + { + Mvc_CubeSetNext( pCube, pList->pHead ); + pList->pHead = pCube; + } + pList->nItems++; +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_ListAddCubeTail_( Mvc_List_t * pList, Mvc_Cube_t * pCube ) +{ + if ( pList->pHead == NULL ) + pList->pHead = pCube; + else + Mvc_CubeSetNext( pList->pTail, pCube ); + pList->pTail = pCube; + Mvc_CubeSetNext( pCube, NULL ); + pList->nItems++; +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_ListDeleteCube_( Mvc_List_t * pList, Mvc_Cube_t * pPrev, Mvc_Cube_t * pCube ) +{ + if ( pPrev == NULL ) // deleting the head cube + pList->pHead = Mvc_CubeReadNext(pCube); + else + pPrev->pNext = pCube->pNext; + if ( pList->pTail == pCube ) // deleting the tail cube + { + assert( Mvc_CubeReadNext(pCube) == NULL ); + pList->pTail = pPrev; + } + pList->nItems--; +} + + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverAddCubeHead_( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube ) +{ + Mvc_List_t * pList = &pCover->lCubes; + if ( pList->pHead == NULL ) + { + Mvc_CubeSetNext( pCube, NULL ); + pList->pHead = pCube; + pList->pTail = pCube; + } + else + { + Mvc_CubeSetNext( pCube, pList->pHead ); + pList->pHead = pCube; + } + pList->nItems++; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverAddCubeTail_( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube ) +{ + Mvc_List_t * pList = &pCover->lCubes; + + if ( pList->pHead == NULL ) + pList->pHead = pCube; + else + Mvc_CubeSetNext( pList->pTail, pCube ); + pList->pTail = pCube; + Mvc_CubeSetNext( pCube, NULL ); + pList->nItems++; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverDeleteCube_( Mvc_Cover_t * pCover, Mvc_Cube_t * pPrev, Mvc_Cube_t * pCube ) +{ + Mvc_List_t * pList = &pCover->lCubes; + + if ( pPrev == NULL ) // deleting the head cube + pList->pHead = Mvc_CubeReadNext(pCube); + else + pPrev->pNext = pCube->pNext; + if ( pList->pTail == pCube ) // deleting the tail cube + { + assert( Mvc_CubeReadNext(pCube) == NULL ); + pList->pTail = pPrev; + } + pList->nItems--; +} + + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverAddDupCubeHead( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube ) +{ + Mvc_Cube_t * pCubeNew; + pCubeNew = Mvc_CubeAlloc( pCover ); + Mvc_CubeBitCopy( pCubeNew, pCube ); + Mvc_CoverAddCubeHead( pCover, pCubeNew ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverAddDupCubeTail( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube ) +{ + Mvc_Cube_t * pCubeNew; + // copy the cube as part of this cover + pCubeNew = Mvc_CubeAlloc( pCover ); + Mvc_CubeBitCopy( pCubeNew, pCube ); + // clean the last bits of the new cube +// pCubeNew->pData[pCubeNew->iLast] &= (BITS_FULL >> pCubeNew->nUnused); + // add the cube at the end + Mvc_CoverAddCubeTail( pCover, pCubeNew ); +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverAddLiteralsOfCube( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube ) +{ +// int iBit, Value; +// assert( pCover->pLits ); +// Mvc_CubeForEachBit( pCover, pCube, iBit, Value ) +// if ( Value ) +// pCover->pLits[iBit] += Value; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverDeleteLiteralsOfCube( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube ) +{ +// int iBit, Value; +// assert( pCover->pLits ); +// Mvc_CubeForEachBit( pCover, pCube, iBit, Value ) +// if ( Value ) +// pCover->pLits[iBit] -= Value; +} + + +/**Function************************************************************* + + Synopsis [Transfers the cubes from the list into the array.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverList2Array( Mvc_Cover_t * pCover ) +{ + Mvc_Cube_t * pCube; + int Counter; + // resize storage if necessary + Mvc_CoverAllocateArrayCubes( pCover ); + // iterate through the cubes + Counter = 0; + Mvc_CoverForEachCube( pCover, pCube ) + pCover->pCubes[ Counter++ ] = pCube; + assert( Counter == Mvc_CoverReadCubeNum(pCover) ); +} + +/**Function************************************************************* + + Synopsis [Transfers the cubes from the array into list.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverArray2List( Mvc_Cover_t * pCover ) +{ + Mvc_Cube_t * pCube; + int nCubes, i; + + assert( pCover->pCubes ); + + nCubes = Mvc_CoverReadCubeNum(pCover); + if ( nCubes == 0 ) + return; + if ( nCubes == 1 ) + { + pCube = pCover->pCubes[0]; + pCube->pNext = NULL; + pCover->lCubes.pHead = pCover->lCubes.pTail = pCube; + return; + } + // set up the first cube + pCube = pCover->pCubes[0]; + pCover->lCubes.pHead = pCube; + // set up the last cube + pCube = pCover->pCubes[nCubes-1]; + pCube->pNext = NULL; + pCover->lCubes.pTail = pCube; + + // link all cubes starting from the first one + for ( i = 0; i < nCubes - 1; i++ ) + pCover->pCubes[i]->pNext = pCover->pCubes[i+1]; +} + +/**Function************************************************************* + + Synopsis [Returns the tail of the linked list given by the head.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Mvc_Cube_t * Mvc_ListGetTailFromHead( Mvc_Cube_t * pHead ) +{ + Mvc_Cube_t * pCube, * pTail; + for ( pTail = pCube = pHead; + pCube; + pTail = pCube, pCube = Mvc_CubeReadNext(pCube) ); + return pTail; +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/misc/mvc/mvcLits.c b/src/misc/mvc/mvcLits.c new file mode 100644 index 00000000..910158e9 --- /dev/null +++ b/src/misc/mvc/mvcLits.c @@ -0,0 +1,345 @@ +/**CFile**************************************************************** + + FileName [mvcLits.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [Literal counting/updating procedures.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: mvcLits.c,v 1.4 2003/04/03 06:31:50 alanmi Exp $] + +***********************************************************************/ + +#include "mvc.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Find the any literal that occurs more than once.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Mvc_CoverAnyLiteral( Mvc_Cover_t * pCover, Mvc_Cube_t * pMask ) +{ + Mvc_Cube_t * pCube; + int nWord, nBit, i; + int nLitsCur; + int fUseFirst = 0; + + // go through each literal + if ( fUseFirst ) + { + for ( i = 0; i < pCover->nBits; i++ ) + if ( !pMask || Mvc_CubeBitValue(pMask,i) ) + { + // get the word and bit of this literal + nWord = Mvc_CubeWhichWord(i); + nBit = Mvc_CubeWhichBit(i); + // go through all the cubes + nLitsCur = 0; + Mvc_CoverForEachCube( pCover, pCube ) + if ( pCube->pData[nWord] & (1< 1 ) + return i; + } + } + } + else + { + for ( i = pCover->nBits - 1; i >=0; i-- ) + if ( !pMask || Mvc_CubeBitValue(pMask,i) ) + { + // get the word and bit of this literal + nWord = Mvc_CubeWhichWord(i); + nBit = Mvc_CubeWhichBit(i); + // go through all the cubes + nLitsCur = 0; + Mvc_CoverForEachCube( pCover, pCube ) + if ( pCube->pData[nWord] & (1< 1 ) + return i; + } + } + } + return -1; +} + +/**Function************************************************************* + + Synopsis [Find the most often occurring literal.] + + Description [Find the most often occurring literal among those + that occur more than once.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Mvc_CoverBestLiteral( Mvc_Cover_t * pCover, Mvc_Cube_t * pMask ) +{ + Mvc_Cube_t * pCube; + int nWord, nBit; + int i, iMax, nLitsMax, nLitsCur; + int fUseFirst = 1; + + // go through each literal + iMax = -1; + nLitsMax = -1; + for ( i = 0; i < pCover->nBits; i++ ) + if ( !pMask || Mvc_CubeBitValue(pMask,i) ) + { + // get the word and bit of this literal + nWord = Mvc_CubeWhichWord(i); + nBit = Mvc_CubeWhichBit(i); + // go through all the cubes + nLitsCur = 0; + Mvc_CoverForEachCube( pCover, pCube ) + if ( pCube->pData[nWord] & (1< 1 ) + return iMax; + return -1; +} + +/**Function************************************************************* + + Synopsis [Find the most often occurring literal.] + + Description [Find the most often occurring literal among those + that occur more than once.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Mvc_CoverWorstLiteral( Mvc_Cover_t * pCover, Mvc_Cube_t * pMask ) +{ + Mvc_Cube_t * pCube; + int nWord, nBit; + int i, iMin, nLitsMin, nLitsCur; + int fUseFirst = 1; + + // go through each literal + iMin = -1; + nLitsMin = 1000000; + for ( i = 0; i < pCover->nBits; i++ ) + if ( !pMask || Mvc_CubeBitValue(pMask,i) ) + { + // get the word and bit of this literal + nWord = Mvc_CubeWhichWord(i); + nBit = Mvc_CubeWhichBit(i); + // go through all the cubes + nLitsCur = 0; + Mvc_CoverForEachCube( pCover, pCube ) + if ( pCube->pData[nWord] & (1< nLitsCur ) + { + nLitsMin = nLitsCur; + iMin = i; + } + } + else + { + if ( nLitsMin >= nLitsCur ) + { + nLitsMin = nLitsCur; + iMin = i; + } + } + } + + if ( nLitsMin < 1000000 ) + return iMin; + return -1; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Mvc_Cover_t * Mvc_CoverBestLiteralCover( Mvc_Cover_t * pCover, Mvc_Cover_t * pSimple ) +{ + Mvc_Cover_t * pCoverNew; + Mvc_Cube_t * pCubeNew; + Mvc_Cube_t * pCubeS; + int iLitBest; + + // create the new cover + pCoverNew = Mvc_CoverClone( pCover ); + // get the new cube + pCubeNew = Mvc_CubeAlloc( pCoverNew ); + // clean the cube + Mvc_CubeBitClean( pCubeNew ); + + // get the first cube of pSimple + assert( Mvc_CoverReadCubeNum(pSimple) == 1 ); + pCubeS = Mvc_CoverReadCubeHead( pSimple ); + // find the best literal among those of pCubeS + iLitBest = Mvc_CoverBestLiteral( pCover, pCubeS ); + + // insert this literal into the cube + Mvc_CubeBitInsert( pCubeNew, iLitBest ); + // add the cube to the cover + Mvc_CoverAddCubeTail( pCoverNew, pCubeNew ); + return pCoverNew; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Mvc_CoverFirstCubeFirstLit( Mvc_Cover_t * pCover ) +{ + Mvc_Cube_t * pCube; + int iBit, Value; + + // get the first cube + pCube = Mvc_CoverReadCubeHead( pCover ); + // get the first literal + Mvc_CubeForEachBit( pCover, pCube, iBit, Value ) + if ( Value ) + return iBit; + return -1; +} + +/**Function************************************************************* + + Synopsis [Returns the number of literals in the cover.] + + Description [Allocates storage for literal counters and fills it up + using the current information.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Mvc_CoverCountLiterals( Mvc_Cover_t * pCover ) +{ + Mvc_Cube_t * pCube; + int nWord, nBit; + int i, CounterTot, CounterCur; + + // allocate/clean the storage for literals +// Mvc_CoverAllocateArrayLits( pCover ); +// memset( pCover->pLits, 0, pCover->nBits * sizeof(int) ); + // go through each literal + CounterTot = 0; + for ( i = 0; i < pCover->nBits; i++ ) + { + // get the word and bit of this literal + nWord = Mvc_CubeWhichWord(i); + nBit = Mvc_CubeWhichBit(i); + // go through all the cubes + CounterCur = 0; + Mvc_CoverForEachCube( pCover, pCube ) + if ( pCube->pData[nWord] & (1< +#include "mvc.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Mvc_Manager_t * Mvc_ManagerStart() +{ + Mvc_Manager_t * p; + p = ALLOC( Mvc_Manager_t, 1 ); + memset( p, 0, sizeof(Mvc_Manager_t) ); + p->pMan1 = Extra_MmFixedStart( sizeof(Mvc_Cube_t) ); + p->pMan2 = Extra_MmFixedStart( sizeof(Mvc_Cube_t) + sizeof(Mvc_CubeWord_t) ); + p->pMan4 = Extra_MmFixedStart( sizeof(Mvc_Cube_t) + 3 * sizeof(Mvc_CubeWord_t) ); + p->pManC = Extra_MmFixedStart( sizeof(Mvc_Cover_t) ); + return p; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_ManagerFree( Mvc_Manager_t * p ) +{ + Extra_MmFixedStop( p->pMan1 ); + Extra_MmFixedStop( p->pMan2 ); + Extra_MmFixedStop( p->pMan4 ); + Extra_MmFixedStop( p->pManC ); + free( p ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/misc/mvc/mvcOpAlg.c b/src/misc/mvc/mvcOpAlg.c new file mode 100644 index 00000000..65c02fa5 --- /dev/null +++ b/src/misc/mvc/mvcOpAlg.c @@ -0,0 +1,163 @@ +/**CFile**************************************************************** + + FileName [mvcOperAlg.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [Miscellaneous operations on covers.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: mvcOpAlg.c,v 1.4 2003/04/26 20:41:36 alanmi Exp $] + +***********************************************************************/ + +#include "mvc.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Multiplies two disjoint-support covers.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Mvc_Cover_t * Mvc_CoverAlgebraicMultiply( Mvc_Cover_t * pCover1, Mvc_Cover_t * pCover2 ) +{ + Mvc_Cover_t * pCover; + Mvc_Cube_t * pCube1, * pCube2, * pCube; + int CompResult; + + // covers should be the same base + assert( pCover1->nBits == pCover2->nBits ); + // make sure that supports do not overlap + Mvc_CoverAllocateMask( pCover1 ); + Mvc_CoverAllocateMask( pCover2 ); + Mvc_CoverSupport( pCover1, pCover1->pMask ); + Mvc_CoverSupport( pCover2, pCover2->pMask ); + // check if the cubes are bit-wise disjoint + Mvc_CubeBitDisjoint( CompResult, pCover1->pMask, pCover2->pMask ); + if ( !CompResult ) + printf( "Mvc_CoverMultiply(): Cover supports are not disjoint!\n" ); + + // iterate through the cubes + pCover = Mvc_CoverClone( pCover1 ); + Mvc_CoverForEachCube( pCover1, pCube1 ) + Mvc_CoverForEachCube( pCover2, pCube2 ) + { + // create the product cube + pCube = Mvc_CubeAlloc( pCover ); + // set the product cube equal to the product of the two cubes + Mvc_CubeBitOr( pCube, pCube1, pCube2 ); + // add the cube to the cover + Mvc_CoverAddCubeTail( pCover, pCube ); + } + return pCover; +} + + +/**Function************************************************************* + + Synopsis [Subtracts the second cover from the first.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Mvc_Cover_t * Mvc_CoverAlgebraicSubtract( Mvc_Cover_t * pCover1, Mvc_Cover_t * pCover2 ) +{ + Mvc_Cover_t * pCover; + Mvc_Cube_t * pCube1, * pCube2, * pCube; + int fFound; + int CompResult; + + // covers should be the same base + assert( pCover1->nBits == pCover2->nBits ); + + // iterate through the cubes + pCover = Mvc_CoverClone( pCover1 ); + Mvc_CoverForEachCube( pCover1, pCube1 ) + { + fFound = 0; + Mvc_CoverForEachCube( pCover2, pCube2 ) + { + Mvc_CubeBitEqual( CompResult, pCube1, pCube2 ); + if ( CompResult ) + { + fFound = 1; + break; + } + } + if ( !fFound ) + { + // create the copy of the cube + pCube = Mvc_CubeDup( pCover, pCube1 ); + // add the cube copy to the cover + Mvc_CoverAddCubeTail( pCover, pCube ); + } + } + return pCover; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Mvc_CoverAlgebraicEqual( Mvc_Cover_t * pCover1, Mvc_Cover_t * pCover2 ) +{ + Mvc_Cube_t * pCube1, * pCube2; + int fFound; + int CompResult; + + // covers should be the same base + assert( pCover1->nBits == pCover2->nBits ); + // iterate through the cubes + Mvc_CoverForEachCube( pCover1, pCube1 ) + { + fFound = 0; + Mvc_CoverForEachCube( pCover2, pCube2 ) + { + Mvc_CubeBitEqual( CompResult, pCube1, pCube2 ); + if ( CompResult ) + { + fFound = 1; + break; + } + } + if ( !fFound ) + return 0; + } + return 1; +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/misc/mvc/mvcOpBool.c b/src/misc/mvc/mvcOpBool.c new file mode 100644 index 00000000..0b34f1de --- /dev/null +++ b/src/misc/mvc/mvcOpBool.c @@ -0,0 +1,151 @@ +/**CFile**************************************************************** + + FileName [mvcProc.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [Various boolean procedures working with covers.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: mvcOpBool.c,v 1.4 2003/04/16 01:55:37 alanmi Exp $] + +***********************************************************************/ + +#include "mvc.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Mvc_Cover_t * Mvc_CoverBooleanOr( Mvc_Cover_t * pCover1, Mvc_Cover_t * pCover2 ) +{ + Mvc_Cover_t * pCover; + Mvc_Cube_t * pCube, * pCubeCopy; + // make sure the covers are compatible + assert( pCover1->nBits == pCover2->nBits ); + // clone the cover + pCover = Mvc_CoverClone( pCover1 ); + // create the cubes by making pair-wise products + // of cubes in pCover1 and pCover2 + Mvc_CoverForEachCube( pCover1, pCube ) + { + pCubeCopy = Mvc_CubeDup( pCover, pCube ); + Mvc_CoverAddCubeTail( pCover, pCubeCopy ); + } + Mvc_CoverForEachCube( pCover2, pCube ) + { + pCubeCopy = Mvc_CubeDup( pCover, pCube ); + Mvc_CoverAddCubeTail( pCover, pCubeCopy ); + } + return pCover; +} + +#if 0 + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Mvc_Cover_t * Mvc_CoverBooleanAnd( Mvc_Data_t * p, Mvc_Cover_t * pCover1, Mvc_Cover_t * pCover2 ) +{ + Mvc_Cover_t * pCover; + Mvc_Cube_t * pCube1, * pCube2, * pCubeCopy; + // make sure the covers are compatible + assert( pCover1->nBits == pCover2->nBits ); + // clone the cover + pCover = Mvc_CoverClone( pCover1 ); + // create the cubes by making pair-wise products + // of cubes in pCover1 and pCover2 + Mvc_CoverForEachCube( pCover1, pCube1 ) + { + Mvc_CoverForEachCube( pCover2, pCube2 ) + { + if ( Mvc_CoverDist0Cubes( p, pCube1, pCube2 ) ) + { + pCubeCopy = Mvc_CubeAlloc( pCover ); + Mvc_CubeBitAnd( pCubeCopy, pCube1, pCube2 ); + Mvc_CoverAddCubeTail( pCover, pCubeCopy ); + } + } + // if the number of cubes in the new cover is too large + // try compressing them + if ( Mvc_CoverReadCubeNum( pCover ) > 500 ) + Mvc_CoverContain( pCover ); + } + return pCover; +} + +/**Function************************************************************* + + Synopsis [Returns 1 if the two covers are equal.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Mvc_CoverBooleanEqual( Mvc_Data_t * p, Mvc_Cover_t * pCover1, Mvc_Cover_t * pCover2 ) +{ + Mvc_Cover_t * pSharp; + + pSharp = Mvc_CoverSharp( p, pCover1, pCover2 ); + if ( Mvc_CoverReadCubeNum( pSharp ) ) + { +Mvc_CoverContain( pSharp ); +printf( "Sharp \n" ); +Mvc_CoverPrint( pSharp ); + Mvc_CoverFree( pSharp ); + return 0; + } + Mvc_CoverFree( pSharp ); + + pSharp = Mvc_CoverSharp( p, pCover2, pCover1 ); + if ( Mvc_CoverReadCubeNum( pSharp ) ) + { +Mvc_CoverContain( pSharp ); +printf( "Sharp \n" ); +Mvc_CoverPrint( pSharp ); + Mvc_CoverFree( pSharp ); + return 0; + } + Mvc_CoverFree( pSharp ); + + return 1; +} + +#endif + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/misc/mvc/mvcPrint.c b/src/misc/mvc/mvcPrint.c new file mode 100644 index 00000000..52ac76b3 --- /dev/null +++ b/src/misc/mvc/mvcPrint.c @@ -0,0 +1,220 @@ +/**CFile**************************************************************** + + FileName [mvcPrint.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [Printing cubes and covers.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: mvcPrint.c,v 1.6 2003/04/09 18:02:06 alanmi Exp $] + +***********************************************************************/ + +#include "mvc.h" +//#include "vm.h" +//#include "vmInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static void Mvc_CubePrintBinary( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverPrint( Mvc_Cover_t * pCover ) +{ + Mvc_Cube_t * pCube; + int i; + // print general statistics + printf( "The cover contains %d cubes (%d bits and %d words)\n", + pCover->lCubes.nItems, pCover->nBits, pCover->nWords ); + // iterate through the cubes + Mvc_CoverForEachCube( pCover, pCube ) + Mvc_CubePrint( pCover, pCube ); + + if ( pCover->pLits ) + { + for ( i = 0; i < pCover->nBits; i++ ) + printf( " %d", pCover->pLits[i] ); + printf( "\n" ); + } + printf( "End of cover printout\n" ); +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CubePrint( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube ) +{ + int iBit, Value; + // iterate through the literals +// printf( "Size = %2d ", Mvc_CubeReadSize(pCube) ); + Mvc_CubeForEachBit( pCover, pCube, iBit, Value ) + printf( "%c", '0' + Value ); + printf( "\n" ); +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverPrintBinary( Mvc_Cover_t * pCover ) +{ + Mvc_Cube_t * pCube; + int i; + // print general statistics + printf( "The cover contains %d cubes (%d bits and %d words)\n", + pCover->lCubes.nItems, pCover->nBits, pCover->nWords ); + // iterate through the cubes + Mvc_CoverForEachCube( pCover, pCube ) + Mvc_CubePrintBinary( pCover, pCube ); + + if ( pCover->pLits ) + { + for ( i = 0; i < pCover->nBits; i++ ) + printf( " %d", pCover->pLits[i] ); + printf( "\n" ); + } + printf( "End of cover printout\n" ); +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CubePrintBinary( Mvc_Cover_t * pCover, Mvc_Cube_t * pCube ) +{ + int iVar, Value; + // iterate through the literals +// printf( "Size = %2d ", Mvc_CubeReadSize(pCube) ); + Mvc_CubeForEachVarValue( pCover, pCube, iVar, Value ) + { + assert( Value != 0 ); + if ( Value == 3 ) + printf( "-" ); + else if ( Value == 1 ) + printf( "0" ); + else + printf( "1" ); + } + printf( "\n" ); +} + +#if 0 + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverPrintMv( Mvc_Data_t * pData, Mvc_Cover_t * pCover ) +{ + Mvc_Cube_t * pCube; + int i; + // print general statistics + printf( "The cover contains %d cubes (%d bits and %d words)\n", + pCover->lCubes.nItems, pCover->nBits, pCover->nWords ); + // iterate through the cubes + Mvc_CoverForEachCube( pCover, pCube ) + Mvc_CubePrintMv( pData, pCover, pCube ); + + if ( pCover->pLits ) + { + for ( i = 0; i < pCover->nBits; i++ ) + printf( " %d", pCover->pLits[i] ); + printf( "\n" ); + } + printf( "End of cover printout\n" ); +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CubePrintMv( Mvc_Data_t * pData, Mvc_Cover_t * pCover, Mvc_Cube_t * pCube ) +{ + int iLit, iVar; + // iterate through the literals + printf( "Size = %2d ", Mvc_CubeReadSize(pCube) ); + iVar = 0; + for ( iLit = 0; iLit < pData->pVm->nValuesIn; iLit++ ) + { + if ( iLit == pData->pVm->pValuesFirst[iVar+1] ) + { + printf( " " ); + iVar++; + } + if ( Mvc_CubeBitValue( pCube, iLit ) ) + printf( "%c", '0' + iLit - pData->pVm->pValuesFirst[iVar] ); + else + printf( "-" ); + } + printf( "\n" ); +} + +#endif + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/misc/mvc/mvcSort.c b/src/misc/mvc/mvcSort.c new file mode 100644 index 00000000..3c975cb3 --- /dev/null +++ b/src/misc/mvc/mvcSort.c @@ -0,0 +1,141 @@ +/**CFile**************************************************************** + + FileName [mvcSort.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [Sorting cubes in the cover with the mask.] + + Author [MVSIS Group] + + Affiliation [uC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: mvcSort.c,v 1.5 2003/04/27 01:03:45 wjiang Exp $] + +***********************************************************************/ + +#include "mvc.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + + +Mvc_Cube_t * Mvc_CoverSort_rec( Mvc_Cube_t * pList, int nItems, Mvc_Cube_t * pMask, int (* pCompareFunc)(Mvc_Cube_t *, Mvc_Cube_t *, Mvc_Cube_t *) ); +Mvc_Cube_t * Mvc_CoverSortMerge( Mvc_Cube_t * pList1, Mvc_Cube_t * pList2, Mvc_Cube_t * pMask, int (* pCompareFunc)(Mvc_Cube_t *, Mvc_Cube_t *, Mvc_Cube_t *) ); + +//////////////////////////////////////////////////////////////////////// +/// FuNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Sorts cubes using the given cost function.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverSort( Mvc_Cover_t * pCover, Mvc_Cube_t * pMask, int (* pCompareFunc)(Mvc_Cube_t *, Mvc_Cube_t *, Mvc_Cube_t *) ) +{ + Mvc_Cube_t * pHead; + int nCubes; + // one cube does not need sorting + nCubes = Mvc_CoverReadCubeNum(pCover); + if ( nCubes <= 1 ) + return; + // sort the cubes + pHead = Mvc_CoverSort_rec( Mvc_CoverReadCubeHead(pCover), nCubes, pMask, pCompareFunc ); + // insert the sorted list into the cover + Mvc_CoverSetCubeHead( pCover, pHead ); + Mvc_CoverSetCubeTail( pCover, Mvc_ListGetTailFromHead(pHead) ); + // make sure that the list is sorted in the increasing order + assert( pCompareFunc( Mvc_CoverReadCubeHead(pCover), Mvc_CoverReadCubeTail(pCover), pMask ) <= 0 ); +} + +/**Function************************************************************* + + Synopsis [Recursive part of Mvc_CoverSort()] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Mvc_Cube_t * Mvc_CoverSort_rec( Mvc_Cube_t * pList, int nItems, Mvc_Cube_t * pMask, int (* pCompareFunc)(Mvc_Cube_t *, Mvc_Cube_t *, Mvc_Cube_t *) ) +{ + Mvc_Cube_t * pList1, * pList2; + int nItems1, nItems2, i; + + // trivial case + if ( nItems == 1 ) + { + Mvc_CubeSetNext( pList, NULL ); + return pList; + } + + // select the new sizes + nItems1 = nItems/2; + nItems2 = nItems - nItems1; + + // set the new beginnings + pList1 = pList2 = pList; + for ( i = 0; i < nItems1; i++ ) + pList2 = Mvc_CubeReadNext( pList2 ); + + // solve recursively + pList1 = Mvc_CoverSort_rec( pList1, nItems1, pMask, pCompareFunc ); + pList2 = Mvc_CoverSort_rec( pList2, nItems2, pMask, pCompareFunc ); + + // merge + return Mvc_CoverSortMerge( pList1, pList2, pMask, pCompareFunc ); +} + + +/**Function************************************************************* + + Synopsis [Merges two NULL-terminated linked lists.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Mvc_Cube_t * Mvc_CoverSortMerge( Mvc_Cube_t * pList1, Mvc_Cube_t * pList2, Mvc_Cube_t * pMask, int (* pCompareFunc)(Mvc_Cube_t *, Mvc_Cube_t *, Mvc_Cube_t *) ) +{ + Mvc_Cube_t * pList = NULL, ** ppTail = &pList; + Mvc_Cube_t * pCube; + while ( pList1 && pList2 ) + { + if ( pCompareFunc( pList1, pList2, pMask ) < 0 ) + { + pCube = pList1; + pList1 = Mvc_CubeReadNext(pList1); + } + else + { + pCube = pList2; + pList2 = Mvc_CubeReadNext(pList2); + } + *ppTail = pCube; + ppTail = Mvc_CubeReadNextP(pCube); + } + *ppTail = pList1? pList1: pList2; + return pList; +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/misc/mvc/mvcUtils.c b/src/misc/mvc/mvcUtils.c new file mode 100644 index 00000000..4b13b23d --- /dev/null +++ b/src/misc/mvc/mvcUtils.c @@ -0,0 +1,868 @@ +/**CFile**************************************************************** + + FileName [mvcUtils.c] + + PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] + + Synopsis [Various cover handling utilities.] + + Author [MVSIS Group] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - February 1, 2003.] + + Revision [$Id: mvcUtils.c,v 1.7 2003/04/26 20:41:36 alanmi Exp $] + +***********************************************************************/ + +#include "mvc.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static int bit_count[256] = { + 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8 +}; + + +static void Mvc_CoverCopyColumn( Mvc_Cover_t * pCoverOld, Mvc_Cover_t * pCoverNew, int iColOld, int iColNew ); + + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverSupport( Mvc_Cover_t * pCover, Mvc_Cube_t * pSupp ) +{ + Mvc_Cube_t * pCube; + // clean the support + Mvc_CubeBitClean( pSupp ); + // collect the support + Mvc_CoverForEachCube( pCover, pCube ) + Mvc_CubeBitOr( pSupp, pSupp, pCube ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverSupportAnd( Mvc_Cover_t * pCover, Mvc_Cube_t * pSupp ) +{ + Mvc_Cube_t * pCube; + // clean the support + Mvc_CubeBitFill( pSupp ); + // collect the support + Mvc_CoverForEachCube( pCover, pCube ) + Mvc_CubeBitAnd( pSupp, pSupp, pCube ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Mvc_CoverSupportSizeBinary( Mvc_Cover_t * pCover ) +{ + Mvc_Cube_t * pSupp; + int Counter, i, v0, v1; + // compute the support + pSupp = Mvc_CubeAlloc( pCover ); + Mvc_CoverSupportAnd( pCover, pSupp ); + Counter = pCover->nBits/2; + for ( i = 0; i < pCover->nBits/2; i++ ) + { + v0 = Mvc_CubeBitValue( pSupp, 2*i ); + v1 = Mvc_CubeBitValue( pSupp, 2*i+1 ); + if ( v0 && v1 ) + Counter--; + } + Mvc_CubeFree( pCover, pSupp ); + return Counter; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Mvc_CoverSupportVarBelongs( Mvc_Cover_t * pCover, int iVar ) +{ + Mvc_Cube_t * pSupp; + int RetValue, v0, v1; + // compute the support + pSupp = Mvc_CubeAlloc( pCover ); + Mvc_CoverSupportAnd( pCover, pSupp ); + v0 = Mvc_CubeBitValue( pSupp, 2*iVar ); + v1 = Mvc_CubeBitValue( pSupp, 2*iVar+1 ); + RetValue = (int)( !v0 || !v1 ); + Mvc_CubeFree( pCover, pSupp ); + return RetValue; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverCommonCube( Mvc_Cover_t * pCover, Mvc_Cube_t * pComCube ) +{ + Mvc_Cube_t * pCube; + // clean the support + Mvc_CubeBitFill( pComCube ); + // collect the support + Mvc_CoverForEachCube( pCover, pCube ) + Mvc_CubeBitAnd( pComCube, pComCube, pCube ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Mvc_CoverIsCubeFree( Mvc_Cover_t * pCover ) +{ + int Result; + // get the common cube + Mvc_CoverAllocateMask( pCover ); + Mvc_CoverCommonCube( pCover, pCover->pMask ); + // check whether the common cube is empty + Mvc_CubeBitEmpty( Result, pCover->pMask ); + return Result; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverMakeCubeFree( Mvc_Cover_t * pCover ) +{ + Mvc_Cube_t * pCube; + // get the common cube + Mvc_CoverAllocateMask( pCover ); + Mvc_CoverCommonCube( pCover, pCover->pMask ); + // remove this cube from the cubes in the cover + Mvc_CoverForEachCube( pCover, pCube ) + Mvc_CubeBitSharp( pCube, pCube, pCover->pMask ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Mvc_Cover_t * Mvc_CoverCommonCubeCover( Mvc_Cover_t * pCover ) +{ + Mvc_Cover_t * pRes; + Mvc_Cube_t * pCube; + // create the new cover + pRes = Mvc_CoverClone( pCover ); + // get the new cube + pCube = Mvc_CubeAlloc( pRes ); + // get the common cube + Mvc_CoverCommonCube( pCover, pCube ); + // add the cube to the cover + Mvc_CoverAddCubeTail( pRes, pCube ); + return pRes; +} + + +/**Function************************************************************* + + Synopsis [Returns 1 if the support of cover2 is contained in the support of cover1.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Mvc_CoverCheckSuppContainment( Mvc_Cover_t * pCover1, Mvc_Cover_t * pCover2 ) +{ + int Result; + assert( pCover1->nBits == pCover2->nBits ); + // set the supports + Mvc_CoverAllocateMask( pCover1 ); + Mvc_CoverSupport( pCover1, pCover1->pMask ); + Mvc_CoverAllocateMask( pCover2 ); + Mvc_CoverSupport( pCover2, pCover2->pMask ); + // check the containment + Mvc_CubeBitNotImpl( Result, pCover2->pMask, pCover1->pMask ); + return !Result; +} + +/**Function************************************************************* + + Synopsis [Counts the cube sizes.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Mvc_CoverSetCubeSizes( Mvc_Cover_t * pCover ) +{ + Mvc_Cube_t * pCube; + unsigned char * pByte, * pByteStart, * pByteStop; + int nBytes, nOnes; + + // get the number of unsigned chars in the cube's bit strings + nBytes = pCover->nBits / (8 * sizeof(unsigned char)) + (int)(pCover->nBits % (8 * sizeof(unsigned char)) > 0); + // iterate through the cubes + Mvc_CoverForEachCube( pCover, pCube ) + { + // clean the counter of ones + nOnes = 0; + // set the starting and stopping positions + pByteStart = (unsigned char *)pCube->pData; + pByteStop = pByteStart + nBytes; + // iterate through the positions + for ( pByte = pByteStart; pByte < pByteStop; pByte++ ) + nOnes += bit_count[*pByte]; + // set the nOnes + Mvc_CubeSetSize( pCube, nOnes ); + } + return 1; +} + +/**Function************************************************************* + + Synopsis [Counts the cube sizes.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Mvc_CoverGetCubeSize( Mvc_Cube_t * pCube ) +{ + unsigned char * pByte, * pByteStart, * pByteStop; + int nOnes, nBytes, nBits; + // get the number of unsigned chars in the cube's bit strings + nBits = (pCube->iLast + 1) * sizeof(Mvc_CubeWord_t) * 8 - pCube->nUnused; + nBytes = nBits / (8 * sizeof(unsigned char)) + (int)(nBits % (8 * sizeof(unsigned char)) > 0); + // clean the counter of ones + nOnes = 0; + // set the starting and stopping positions + pByteStart = (unsigned char *)pCube->pData; + pByteStop = pByteStart + nBytes; + // iterate through the positions + for ( pByte = pByteStart; pByte < pByteStop; pByte++ ) + nOnes += bit_count[*pByte]; + return nOnes; +} + +/**Function************************************************************* + + Synopsis [Counts the differences in each cube pair in the cover.] + + Description [Takes the cover (pCover) and the array where the + diff counters go (pDiffs). The array pDiffs should have as many + entries as there are different pairs of cubes in the cover: n(n-1)/2. + Fills out the array pDiffs with the following info: For each cube + pair, included in the array is the number of literals in both cubes + after they are made cube free.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Mvc_CoverCountCubePairDiffs( Mvc_Cover_t * pCover, unsigned char pDiffs[] ) +{ + Mvc_Cube_t * pCube1; + Mvc_Cube_t * pCube2; + Mvc_Cube_t * pMask; + unsigned char * pByte, * pByteStart, * pByteStop; + int nBytes, nOnes; + int nCubePairs; + + // allocate a temporary mask + pMask = Mvc_CubeAlloc( pCover ); + // get the number of unsigned chars in the cube's bit strings + nBytes = pCover->nBits / (8 * sizeof(unsigned char)) + (int)(pCover->nBits % (8 * sizeof(unsigned char)) > 0); + // iterate through the cubes + nCubePairs = 0; + Mvc_CoverForEachCube( pCover, pCube1 ) + { + Mvc_CoverForEachCubeStart( Mvc_CubeReadNext(pCube1), pCube2 ) + { + // find the bit-wise exor of cubes + Mvc_CubeBitExor( pMask, pCube1, pCube2 ); + // set the starting and stopping positions + pByteStart = (unsigned char *)pMask->pData; + pByteStop = pByteStart + nBytes; + // clean the counter of ones + nOnes = 0; + // iterate through the positions + for ( pByte = pByteStart; pByte < pByteStop; pByte++ ) + nOnes += bit_count[*pByte]; + // set the nOnes + pDiffs[nCubePairs++] = nOnes; + } + } + // deallocate the mask + Mvc_CubeFree( pCover, pMask ); + return 1; +} + + +/**Function************************************************************* + + Synopsis [Creates a new cover containing some literals of the old cover.] + + Description [Creates the new cover containing the given number (nVarsRem) + literals of the old cover. All the bits of the new cover are initialized + to "1". The selected bits from the old cover are copied on top. The numbers + of the selected bits to copy are given in the array pVarsRem. The i-set + entry in this array is the index of the bit in the old cover which goes + to the i-th place in the new cover. If the i-th entry in pVarsRem is -1, + it means that the i-th bit does not change (remains composed of all 1's). + This is a useful feature to speed up remapping covers, which are known + to depend only on a subset of input variables.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Mvc_Cover_t * Mvc_CoverRemap( Mvc_Cover_t * p, int * pVarsRem, int nVarsRem ) +{ + Mvc_Cover_t * pCover; + Mvc_Cube_t * pCube, * pCubeCopy; + int i; + // clone the cover + pCover = Mvc_CoverAlloc( p->pMem, nVarsRem ); + // copy the cube list + Mvc_CoverForEachCube( p, pCube ) + { + pCubeCopy = Mvc_CubeAlloc( pCover ); + //Mvc_CubeBitClean( pCubeCopy ); //changed by wjiang + Mvc_CubeBitFill( pCubeCopy ); //changed by wjiang + Mvc_CoverAddCubeTail( pCover, pCubeCopy ); + } + // copy the corresponding columns + for ( i = 0; i < nVarsRem; i++ ) + { + if (pVarsRem[i] < 0) + continue; //added by wjiang + assert( pVarsRem[i] >= 0 && pVarsRem[i] < p->nBits ); + Mvc_CoverCopyColumn( p, pCover, pVarsRem[i], i ); + } + return pCover; +} + +/**Function************************************************************* + + Synopsis [Copies a column from the old cover to the new cover.] + + Description [Copies the column (iColOld) of the old cover (pCoverOld) + into the column (iColNew) of the new cover (pCoverNew). Assumes that + the number of cubes is the same in both covers. Makes no assuptions + about the current contents of the column in the new cover.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverCopyColumn( Mvc_Cover_t * pCoverOld, Mvc_Cover_t * pCoverNew, + int iColOld, int iColNew ) +{ + Mvc_Cube_t * pCubeOld, * pCubeNew; + int iWordOld, iWordNew, iBitOld, iBitNew; + + assert( Mvc_CoverReadCubeNum(pCoverOld) == Mvc_CoverReadCubeNum(pCoverNew) ); + + // get the place of the old and new columns + iWordOld = Mvc_CubeWhichWord(iColOld); + iBitOld = Mvc_CubeWhichBit(iColOld); + iWordNew = Mvc_CubeWhichWord(iColNew); + iBitNew = Mvc_CubeWhichBit(iColNew); + + // go through the cubes of both covers + pCubeNew = Mvc_CoverReadCubeHead(pCoverNew); + Mvc_CoverForEachCube( pCoverOld, pCubeOld ) + { + if ( pCubeOld->pData[iWordOld] & (1<pData[iWordNew] |= (1<pData[iWordNew] &= ~(1<pVm, iVar); + nValues = Vm_VarMapReadValues(pData->pVm, iVar); + ppCofs = ALLOC( Mvc_Cover_t *, nValues + 1 ); + for ( i = 0; i <= nValues; i++ ) + ppCofs[i] = Mvc_CoverClone( pCover ); + + // go through the cubes + Mvc_CoverForEachCube( pCover, pCube ) + { + // if the literal if a full literal, add it to last "cofactor" + Mvc_CubeBitEqualUnderMask( Res, pCube, pData->ppMasks[iVar], pData->ppMasks[iVar] ); + if ( Res ) + { + pCubeNew = Mvc_CubeDup(pCover, pCube); + Mvc_CoverAddCubeTail( ppCofs[nValues], pCubeNew ); + continue; + } + + // otherwise, add it to separate values + for ( i = 0; i < nValues; i++ ) + if ( Mvc_CubeBitValue( pCube, iValueFirst + i ) ) + { + pCubeNew = Mvc_CubeDup(pCover, pCube); + Mvc_CubeBitOr( pCubeNew, pCubeNew, pData->ppMasks[iVar] ); + Mvc_CoverAddCubeTail( ppCofs[i], pCubeNew ); + } + } + return ppCofs; +} + +/**Function************************************************************* + + Synopsis [Count the cubes with non-trivial literals with the given value.] + + Description [The data and the cover are given (pData, pCover). Also given + are the variable number and the number of a value of this variable. + This procedure returns the number of cubes having a non-trivial literal + of this variable that have the given value present.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Mvr_CoverCountLitsWithValue( Mvc_Data_t * pData, Mvc_Cover_t * pCover, int iVar, int iValue ) +{ + Mvc_Cube_t * pCube; + int iValueFirst, Res, Counter; + + Counter = 0; + iValueFirst = Vm_VarMapReadValuesFirst( pData->pVm, iVar ); + Mvc_CoverForEachCube( pCover, pCube ) + { + // check if the given literal is the full literal + Mvc_CubeBitEqualUnderMask( Res, pCube, pData->ppMasks[iVar], pData->ppMasks[iVar] ); + if ( Res ) + continue; + // this literal is not a full literal; check if it has this value + Counter += Mvc_CubeBitValue( pCube, iValueFirst + iValue ); + } + return Counter; +} + +/**Function************************************************************* + + Synopsis [Creates the expanded cover.] + + Description [The original cover is expanded by adding some variables. + These variables are the additional variables in pVmNew, compared to + pCvr->pVm. The resulting cover is the same as the original one, except + that it contains the additional variables present as full literals + in every cube.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Mvc_Cover_t * Mvc_CoverCreateExpanded( Mvc_Cover_t * pCover, Vm_VarMap_t * pVmNew ) +{ + Mvc_Cover_t * pCoverNew; + Mvc_Cube_t * pCube, * pCubeNew; + int i, iLast, iLastNew; + + // create the new cover + pCoverNew = Mvc_CoverAlloc( pCover->pMem, Vm_VarMapReadValuesInNum(pVmNew) ); + + // get the cube composed of extra bits + Mvc_CoverAllocateMask( pCoverNew ); + Mvc_CubeBitClean( pCoverNew->pMask ); + for ( i = pCover->nBits; i < pCoverNew->nBits; i++ ) + Mvc_CubeBitInsert( pCoverNew->pMask, i ); + + // get the indexes of the last words in both covers + iLast = pCover->nWords? pCover->nWords - 1: 0; + iLastNew = pCoverNew->nWords? pCoverNew->nWords - 1: 0; + + // create the cubes of the new cover + Mvc_CoverForEachCube( pCover, pCube ) + { + pCubeNew = Mvc_CubeAlloc( pCoverNew ); + Mvc_CubeBitClean( pCubeNew ); + // copy the bits (cannot immediately use Mvc_CubeBitCopy, + // because covers have different numbers of bits) + Mvc_CubeSetLast( pCubeNew, iLast ); + Mvc_CubeBitCopy( pCubeNew, pCube ); + Mvc_CubeSetLast( pCubeNew, iLastNew ); + // add the extra bits + Mvc_CubeBitOr( pCubeNew, pCubeNew, pCoverNew->pMask ); + // add the cube to the new cover + Mvc_CoverAddCubeTail( pCoverNew, pCubeNew ); + } + return pCoverNew; +} + +#endif + +/**Function************************************************************* + + Synopsis [Transposes the cube cover.] + + Description [Returns the cube cover that looks like a transposed + matrix, compared to the matrix derived from the original cover.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Mvc_Cover_t * Mvc_CoverTranspose( Mvc_Cover_t * pCover ) +{ + Mvc_Cover_t * pRes; + Mvc_Cube_t * pCubeRes, * pCube; + int nWord, nBit, i, iCube; + + pRes = Mvc_CoverAlloc( pCover->pMem, Mvc_CoverReadCubeNum(pCover) ); + for ( i = 0; i < pCover->nBits; i++ ) + { + // get the word and bit of this literal + nWord = Mvc_CubeWhichWord(i); + nBit = Mvc_CubeWhichBit(i); + // get the transposed cube + pCubeRes = Mvc_CubeAlloc( pRes ); + Mvc_CubeBitClean( pCubeRes ); + iCube = 0; + Mvc_CoverForEachCube( pCover, pCube ) + { + if ( pCube->pData[nWord] & (1<nUnused == 0 ) + continue; + + Unsigned = ( pCube->pData[pCube->iLast] & + (BITS_FULL << (32-pCube->nUnused)) ); + if( Unsigned ) + { + printf( "Cube %2d out of %2d contains dirty bits.\n", nCubes, + Mvc_CoverReadCubeNum(pCover) ); + } + nCubes++; + } + return 1; +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/misc/nm/module.make b/src/misc/nm/module.make new file mode 100644 index 00000000..2a3820c7 --- /dev/null +++ b/src/misc/nm/module.make @@ -0,0 +1,2 @@ +SRC += src/misc/nm/nmApi.c \ + src/misc/nm/nmTable.c diff --git a/src/misc/nm/nm.h b/src/misc/nm/nm.h new file mode 100644 index 00000000..c6344bbf --- /dev/null +++ b/src/misc/nm/nm.h @@ -0,0 +1,92 @@ +/**CFilextern e**************************************************************** + + FileName [nm.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Name manager.] + + Synopsis [External declarations.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: nm.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#ifndef __NM_H__ +#define __NM_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + This manager is designed to store ID-to-name and name-to-ID mapping + for Boolean networks and And-Inverter Graphs. + + In a netlist, net names are unique. In this case, there is a one-to-one + mapping between IDs and names. + + In a logic network, which do not have nets, several objects may have + the same name. For example, a latch output and a primary output. + Another example, a primary input and an input to a black box. + In this case, for each ID on an object there is only one name, + but for each name may be several IDs of objects having this name. + + The name manager maps ID-to-name uniquely but it allows one name to + be mapped into several IDs. When a query to find an ID of the object + by its name is submitted, it is possible to specify the object type, + which will help select one of several IDs. If the type is -1, and + there is more than one object with the given name, any object with + the given name is returned. +*/ + +//////////////////////////////////////////////////////////////////////// +/// INCLUDES /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// PARAMETERS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// BASIC TYPES /// +//////////////////////////////////////////////////////////////////////// + +typedef struct Nm_Man_t_ Nm_Man_t; + +//////////////////////////////////////////////////////////////////////// +/// MACRO DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +/*=== nmApi.c ==========================================================*/ +extern Nm_Man_t * Nm_ManCreate( int nSize ); +extern void Nm_ManFree( Nm_Man_t * p ); +extern int Nm_ManNumEntries( Nm_Man_t * p ); +extern char * Nm_ManStoreIdName( Nm_Man_t * p, int ObjId, int Type, char * pName, char * pSuffix ); +extern void Nm_ManDeleteIdName( Nm_Man_t * p, int ObjId ); +extern char * Nm_ManCreateUniqueName( Nm_Man_t * p, int ObjId ); +extern char * Nm_ManFindNameById( Nm_Man_t * p, int ObjId ); +extern int Nm_ManFindIdByName( Nm_Man_t * p, char * pName, int Type ); +extern int Nm_ManFindIdByNameTwoTypes( Nm_Man_t * p, char * pName, int Type1, int Type2 ); +extern Vec_Int_t * Nm_ManReturnNameIds( Nm_Man_t * p ); + +#ifdef __cplusplus +} +#endif + +#endif + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + diff --git a/src/misc/nm/nmApi.c b/src/misc/nm/nmApi.c new file mode 100644 index 00000000..9165922f --- /dev/null +++ b/src/misc/nm/nmApi.c @@ -0,0 +1,272 @@ +/**CFile**************************************************************** + + FileName [nmApi.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Name manager.] + + Synopsis [APIs of the name manager.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: nmApi.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "nmInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Allocates the name manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Nm_Man_t * Nm_ManCreate( int nSize ) +{ + Nm_Man_t * p; + // allocate the table + p = ALLOC( Nm_Man_t, 1 ); + memset( p, 0, sizeof(Nm_Man_t) ); + // set the parameters + p->nSizeFactor = 2; // determined the limit on the grow of data before the table resizes + p->nGrowthFactor = 3; // determined how much the table grows after resizing + // allocate and clean the bins + p->nBins = Cudd_PrimeNm(nSize); + p->pBinsI2N = ALLOC( Nm_Entry_t *, p->nBins ); + p->pBinsN2I = ALLOC( Nm_Entry_t *, p->nBins ); + memset( p->pBinsI2N, 0, sizeof(Nm_Entry_t *) * p->nBins ); + memset( p->pBinsN2I, 0, sizeof(Nm_Entry_t *) * p->nBins ); + // start the memory manager + p->pMem = Extra_MmFlexStart(); + return p; +} + +/**Function************************************************************* + + Synopsis [Deallocates the name manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Nm_ManFree( Nm_Man_t * p ) +{ + Extra_MmFlexStop( p->pMem ); + FREE( p->pBinsI2N ); + FREE( p->pBinsN2I ); + FREE( p ); +} + +/**Function************************************************************* + + Synopsis [Returns the number of objects with names.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Nm_ManNumEntries( Nm_Man_t * p ) +{ + return p->nEntries; +} + +/**Function************************************************************* + + Synopsis [Creates a new entry in the name manager.] + + Description [Returns 1 if the entry with the given object ID + already exists in the name manager.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +char * Nm_ManStoreIdName( Nm_Man_t * p, int ObjId, int Type, char * pName, char * pSuffix ) +{ + Nm_Entry_t * pEntry; + int RetValue, nEntrySize; + // check if the object with this ID is already stored + if ( pEntry = Nm_ManTableLookupId(p, ObjId) ) + { + printf( "Nm_ManStoreIdName(): Entry with the same ID already exists.\n" ); + return NULL; + } + // create a new entry + nEntrySize = sizeof(Nm_Entry_t) + strlen(pName) + (pSuffix?strlen(pSuffix):0) + 1; + nEntrySize = (nEntrySize / 4 + ((nEntrySize % 4) > 0)) * 4; + pEntry = (Nm_Entry_t *)Extra_MmFlexEntryFetch( p->pMem, nEntrySize ); + pEntry->pNextI2N = pEntry->pNextN2I = pEntry->pNameSake = NULL; + pEntry->ObjId = ObjId; + pEntry->Type = Type; + sprintf( pEntry->Name, "%s%s", pName, pSuffix? pSuffix : "" ); + // add the entry to the hash table + RetValue = Nm_ManTableAdd( p, pEntry ); + assert( RetValue == 1 ); + return pEntry->Name; +} + +/**Function************************************************************* + + Synopsis [Creates a new entry in the name manager.] + + Description [Returns 1 if the entry with the given object ID + already exists in the name manager.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Nm_ManDeleteIdName( Nm_Man_t * p, int ObjId ) +{ + Nm_Entry_t * pEntry; + pEntry = Nm_ManTableLookupId(p, ObjId); + if ( pEntry == NULL ) + { + printf( "Nm_ManDeleteIdName(): This entry is not in the table.\n" ); + return; + } + // remove entry from the table + Nm_ManTableDelete( p, ObjId ); +} + + +/**Function************************************************************* + + Synopsis [Finds a unique name for the node.] + + Description [If the name exists, tries appending numbers to it until + it becomes unique. The name is not added to the table.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +char * Nm_ManCreateUniqueName( Nm_Man_t * p, int ObjId ) +{ + static char NameStr[1000]; + Nm_Entry_t * pEntry; + int i; + if ( pEntry = Nm_ManTableLookupId(p, ObjId) ) + return pEntry->Name; + sprintf( NameStr, "n%d", ObjId ); + for ( i = 1; Nm_ManTableLookupName(p, NameStr, -1); i++ ) + sprintf( NameStr, "n%d_%d", ObjId, i ); + return NameStr; +} + +/**Function************************************************************* + + Synopsis [Returns name of the object if the ID is known.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +char * Nm_ManFindNameById( Nm_Man_t * p, int ObjId ) +{ + Nm_Entry_t * pEntry; + if ( pEntry = Nm_ManTableLookupId(p, ObjId) ) + return pEntry->Name; + return NULL; +} + +/**Function************************************************************* + + Synopsis [Returns ID of the object if its name is known.] + + Description [This procedure may return two IDs because POs and latches + may have the same name (the only allowed case of name duplication).] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Nm_ManFindIdByName( Nm_Man_t * p, char * pName, int Type ) +{ + Nm_Entry_t * pEntry; + if ( pEntry = Nm_ManTableLookupName(p, pName, Type) ) + return pEntry->ObjId; + return -1; +} + +/**Function************************************************************* + + Synopsis [Returns ID of the object if its name is known.] + + Description [This procedure may return two IDs because POs and latches + may have the same name (the only allowed case of name duplication).] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Nm_ManFindIdByNameTwoTypes( Nm_Man_t * p, char * pName, int Type1, int Type2 ) +{ + int iNodeId; + iNodeId = Nm_ManFindIdByName( p, pName, Type1 ); + if ( iNodeId == -1 ) + iNodeId = Nm_ManFindIdByName( p, pName, Type2 ); + if ( iNodeId == -1 ) + return -1; + return iNodeId; +} + +/**Function************************************************************* + + Synopsis [Return the IDs of objects with names.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Int_t * Nm_ManReturnNameIds( Nm_Man_t * p ) +{ + Vec_Int_t * vNameIds; + int i; + vNameIds = Vec_IntAlloc( p->nEntries ); + for ( i = 0; i < p->nBins; i++ ) + if ( p->pBinsI2N[i] ) + Vec_IntPush( vNameIds, p->pBinsI2N[i]->ObjId ); + return vNameIds; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/misc/nm/nmInt.h b/src/misc/nm/nmInt.h new file mode 100644 index 00000000..028316e1 --- /dev/null +++ b/src/misc/nm/nmInt.h @@ -0,0 +1,91 @@ +/**CFile**************************************************************** + + FileName [nmInt.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Name manager.] + + Synopsis [Internal declarations.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: nmInt.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#ifndef __NM_INT_H__ +#define __NM_INT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +//////////////////////////////////////////////////////////////////////// +/// INCLUDES /// +//////////////////////////////////////////////////////////////////////// + +#include "extra.h" +#include "vec.h" +#include "nm.h" + +//////////////////////////////////////////////////////////////////////// +/// PARAMETERS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// BASIC TYPES /// +//////////////////////////////////////////////////////////////////////// + +typedef struct Nm_Entry_t_ Nm_Entry_t; +struct Nm_Entry_t_ +{ + unsigned Type : 4; // object type + unsigned ObjId : 28; // object ID + Nm_Entry_t * pNextI2N; // the next entry in the ID hash table + Nm_Entry_t * pNextN2I; // the next entry in the name hash table + Nm_Entry_t * pNameSake; // the next entry with the same name + char Name[0]; // name of the object +}; + +struct Nm_Man_t_ +{ + Nm_Entry_t ** pBinsI2N; // mapping IDs into names + Nm_Entry_t ** pBinsN2I; // mapping names into IDs + int nBins; // the number of bins in tables + int nEntries; // the number of entries + int nSizeFactor; // determined how much larger the table should be + int nGrowthFactor; // determined how much the table grows after resizing + Extra_MmFlex_t * pMem; // memory manager for entries (and names) +}; + +//////////////////////////////////////////////////////////////////////// +/// MACRO DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +/*=== nmTable.c ==========================================================*/ +extern int Nm_ManTableAdd( Nm_Man_t * p, Nm_Entry_t * pEntry ); +extern int Nm_ManTableDelete( Nm_Man_t * p, int ObjId ); +extern Nm_Entry_t * Nm_ManTableLookupId( Nm_Man_t * p, int ObjId ); +extern Nm_Entry_t * Nm_ManTableLookupName( Nm_Man_t * p, char * pName, int Type ); +extern unsigned int Cudd_PrimeNm( unsigned int p ); + +#ifdef __cplusplus +} +#endif + +#endif + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/misc/nm/nmTable.c b/src/misc/nm/nmTable.c new file mode 100644 index 00000000..f97a2f0b --- /dev/null +++ b/src/misc/nm/nmTable.c @@ -0,0 +1,340 @@ +/**CFile**************************************************************** + + FileName [nmTable.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Name manager.] + + Synopsis [Hash table for the name manager.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: nmTable.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "nmInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +// hashing for integers +static unsigned Nm_HashNumber( int Num, int TableSize ) +{ + unsigned Key = 0; + Key ^= ( Num & 0xFF) * 7937; + Key ^= ((Num >> 8) & 0xFF) * 2971; + Key ^= ((Num >> 16) & 0xFF) * 911; + Key ^= ((Num >> 24) & 0xFF) * 353; + return Key % TableSize; +} + +// hashing for strings +static unsigned Nm_HashString( char * pName, int TableSize ) +{ + static int s_Primes[10] = { + 1291, 1699, 2357, 4177, 5147, + 5647, 6343, 7103, 7873, 8147 + }; + unsigned i, Key = 0; + for ( i = 0; pName[i] != '\0'; i++ ) + Key ^= s_Primes[i%10]*pName[i]*pName[i]; + return Key % TableSize; +} + +static void Nm_ManResize( Nm_Man_t * p ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Adds an entry to two hash tables.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Nm_ManTableAdd( Nm_Man_t * p, Nm_Entry_t * pEntry ) +{ + Nm_Entry_t ** ppSpot, * pOther; + // resize the tables if needed + if ( p->nEntries > p->nBins * p->nSizeFactor ) + Nm_ManResize( p ); + // add the entry to the table Id->Name + assert( Nm_ManTableLookupId(p, pEntry->ObjId) == NULL ); + ppSpot = p->pBinsI2N + Nm_HashNumber(pEntry->ObjId, p->nBins); + pEntry->pNextI2N = *ppSpot; + *ppSpot = pEntry; + // check if an entry with the same name already exists + if ( pOther = Nm_ManTableLookupName(p, pEntry->Name, -1) ) + { + // entry with the same name already exists - add it to the ring + pEntry->pNameSake = pOther->pNameSake? pOther->pNameSake : pOther; + pOther->pNameSake = pEntry; + } + else + { + // entry with the same name does not exist - add it to the table + ppSpot = p->pBinsN2I + Nm_HashString(pEntry->Name, p->nBins); + pEntry->pNextN2I = *ppSpot; + *ppSpot = pEntry; + } + // report successfully added entry + p->nEntries++; + return 1; +} + +/**Function************************************************************* + + Synopsis [Deletes the entry from two hash tables.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Nm_ManTableDelete( Nm_Man_t * p, int ObjId ) +{ + Nm_Entry_t ** ppSpot, * pEntry, * pPrev; + int fRemoved; + p->nEntries--; + // remove the entry from the table Id->Name + assert( Nm_ManTableLookupId(p, ObjId) != NULL ); + ppSpot = p->pBinsI2N + Nm_HashNumber(ObjId, p->nBins); + while ( (*ppSpot)->ObjId != (unsigned)ObjId ) + ppSpot = &(*ppSpot)->pNextI2N; + pEntry = *ppSpot; + *ppSpot = (*ppSpot)->pNextI2N; + // remove the entry from the table Name->Id + ppSpot = p->pBinsN2I + Nm_HashString(pEntry->Name, p->nBins); + while ( *ppSpot && *ppSpot != pEntry ) + ppSpot = &(*ppSpot)->pNextN2I; + // remember if we found this one in the list + fRemoved = (*ppSpot != NULL); + if ( *ppSpot ) + { + assert( *ppSpot == pEntry ); + *ppSpot = (*ppSpot)->pNextN2I; + } + // quit if this entry has no namesakes + if ( pEntry->pNameSake == NULL ) + { + assert( fRemoved ); + return 1; + } + // remove entry from the ring of namesakes + assert( pEntry->pNameSake != pEntry ); + for ( pPrev = pEntry; pPrev->pNameSake != pEntry; pPrev = pPrev->pNameSake ); + assert( !strcmp(pPrev->Name, pEntry->Name) ); + assert( pPrev->pNameSake == pEntry ); + if ( pEntry->pNameSake == pPrev ) // two entries in the ring + pPrev->pNameSake = NULL; + else + pPrev->pNameSake = pEntry->pNameSake; + // reinsert the ring back if we removed its connection with the list in the table + if ( fRemoved ) + { + assert( pPrev->pNextN2I == NULL ); + pPrev->pNextN2I = *ppSpot; + *ppSpot = pPrev; + } + return 1; +} + +/**Function************************************************************* + + Synopsis [Looks up the entry by ID.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Nm_Entry_t * Nm_ManTableLookupId( Nm_Man_t * p, int ObjId ) +{ + Nm_Entry_t * pEntry; + for ( pEntry = p->pBinsI2N[ Nm_HashNumber(ObjId, p->nBins) ]; pEntry; pEntry = pEntry->pNextI2N ) + if ( pEntry->ObjId == (unsigned)ObjId ) + return pEntry; + return NULL; +} + +/**Function************************************************************* + + Synopsis [Looks up the entry by name and type.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Nm_Entry_t * Nm_ManTableLookupName( Nm_Man_t * p, char * pName, int Type ) +{ + Nm_Entry_t * pEntry, * pTemp; + int Counter = 0; + for ( pEntry = p->pBinsN2I[ Nm_HashString(pName, p->nBins) ]; pEntry; pEntry = pEntry->pNextN2I ) + { + // check the entry itself + if ( !strcmp(pEntry->Name, pName) && (Type == -1 || pEntry->Type == (unsigned)Type) ) + return pEntry; + // if there is no namesakes, continue + if ( pEntry->pNameSake == NULL ) + continue; + // check the list of namesakes + for ( pTemp = pEntry->pNameSake; pTemp != pEntry; pTemp = pTemp->pNameSake ) + if ( !strcmp(pTemp->Name, pName) && (Type == -1 || pTemp->Type == (unsigned)Type) ) + return pTemp; + } + return NULL; +} + +/**Function************************************************************* + + Synopsis [Profiles hash tables.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Nm_ManProfile( Nm_Man_t * p ) +{ + Nm_Entry_t * pEntry; + int Counter, e; + printf( "I2N table: " ); + for ( e = 0; e < p->nBins; e++ ) + { + Counter = 0; + for ( pEntry = p->pBinsI2N[e]; pEntry; pEntry = pEntry->pNextI2N ) + Counter++; + printf( "%d ", Counter ); + } + printf( "\n" ); + printf( "N2I table: " ); + for ( e = 0; e < p->nBins; e++ ) + { + Counter = 0; + for ( pEntry = p->pBinsN2I[e]; pEntry; pEntry = pEntry->pNextN2I ) + Counter++; + printf( "%d ", Counter ); + } + printf( "\n" ); +} + +/**Function************************************************************* + + Synopsis [Resizes the table.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Nm_ManResize( Nm_Man_t * p ) +{ + Nm_Entry_t ** pBinsNewI2N, ** pBinsNewN2I, * pEntry, * pEntry2, ** ppSpot; + int nBinsNew, Counter, e, clk; + +clk = clock(); + // get the new table size + nBinsNew = Cudd_PrimeCopy( p->nGrowthFactor * p->nBins ); + // allocate a new array + pBinsNewI2N = ALLOC( Nm_Entry_t *, nBinsNew ); + pBinsNewN2I = ALLOC( Nm_Entry_t *, nBinsNew ); + memset( pBinsNewI2N, 0, sizeof(Nm_Entry_t *) * nBinsNew ); + memset( pBinsNewN2I, 0, sizeof(Nm_Entry_t *) * nBinsNew ); + // rehash entries in Id->Name table + Counter = 0; + for ( e = 0; e < p->nBins; e++ ) + for ( pEntry = p->pBinsI2N[e], pEntry2 = pEntry? pEntry->pNextI2N : NULL; + pEntry; pEntry = pEntry2, pEntry2 = pEntry? pEntry->pNextI2N : NULL ) + { + ppSpot = pBinsNewI2N + Nm_HashNumber(pEntry->ObjId, nBinsNew); + pEntry->pNextI2N = *ppSpot; + *ppSpot = pEntry; + Counter++; + } + // rehash entries in Name->Id table + for ( e = 0; e < p->nBins; e++ ) + for ( pEntry = p->pBinsN2I[e], pEntry2 = pEntry? pEntry->pNextN2I : NULL; + pEntry; pEntry = pEntry2, pEntry2 = pEntry? pEntry->pNextN2I : NULL ) + { + ppSpot = pBinsNewN2I + Nm_HashString(pEntry->Name, nBinsNew); + pEntry->pNextN2I = *ppSpot; + *ppSpot = pEntry; + } + assert( Counter == p->nEntries ); +// printf( "Increasing the structural table size from %6d to %6d. ", p->nBins, nBinsNew ); +// PRT( "Time", clock() - clk ); + // replace the table and the parameters + free( p->pBinsI2N ); + free( p->pBinsN2I ); + p->pBinsI2N = pBinsNewI2N; + p->pBinsN2I = pBinsNewN2I; + p->nBins = nBinsNew; +// Nm_ManProfile( p ); +} + + +/**Function************************************************************* + + Synopsis [Returns the smallest prime larger than the number.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +unsigned int Cudd_PrimeNm( unsigned int p) +{ + int i,pn; + + p--; + do { + p++; + if (p&1) { + pn = 1; + i = 3; + while ((unsigned) (i * i) <= p) { + if (p % i == 0) { + pn = 0; + break; + } + i += 2; + } + } else { + pn = 0; + } + } while (!pn); + return(p); + +} /* end of Cudd_Prime */ + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/misc/st/module.make b/src/misc/st/module.make new file mode 100644 index 00000000..33e442c0 --- /dev/null +++ b/src/misc/st/module.make @@ -0,0 +1,2 @@ +SRC += src/misc/st/st.c \ + src/misc/st/stmm.c diff --git a/src/misc/st/st.c b/src/misc/st/st.c new file mode 100644 index 00000000..872fe51b --- /dev/null +++ b/src/misc/st/st.c @@ -0,0 +1,625 @@ +/* + * Revision Control Information + * + * /projects/hsis/CVS/utilities/st/st.c,v + * serdar + * 1.1 + * 1993/07/29 01:00:13 + * + */ +#include +#include +#include "st.h" + +#ifndef ABS +# define ABS(a) ((a) < 0 ? -(a) : (a)) +#endif + +#ifndef ALLOC +#define ALLOC(type, num) ((type *) malloc(sizeof(type) * (num))) +#endif + +#ifndef FREE +#define FREE(obj) ((obj) ? (free((char *) (obj)), (obj) = 0) : 0) +#endif + +#ifndef REALLOC +#define REALLOC(type, obj, num) \ + ((obj) ? ((type *) realloc((char *)(obj), sizeof(type) * (num))) : \ + ((type *) malloc(sizeof(type) * (num)))) +#endif + +#define ST_NUMCMP(x,y) ((x) != (y)) +#define ST_NUMHASH(x,size) (ABS((long)x)%(size)) +//#define ST_PTRHASH(x,size) ((int)((unsigned long)(x)>>2)%size) // 64-bit bug fix 9/17/2007 +#define ST_PTRHASH(x,size) ((int)(((unsigned long)(x)>>2)%size)) +#define EQUAL(func, x, y) \ + ((((func) == st_numcmp) || ((func) == st_ptrcmp)) ?\ + (ST_NUMCMP((x),(y)) == 0) : ((*func)((x), (y)) == 0)) + + +#define do_hash(key, table)\ + ((table->hash == st_ptrhash) ? ST_PTRHASH((key),(table)->num_bins) :\ + (table->hash == st_numhash) ? ST_NUMHASH((key), (table)->num_bins) :\ + (*table->hash)((key), (table)->num_bins)) + +static int rehash(); +int st_numhash(), st_ptrhash(), st_numcmp(), st_ptrcmp(); + +st_table * +st_init_table_with_params(compare, hash, size, density, grow_factor, + reorder_flag) +int (*compare)(); +int (*hash)(); +int size; +int density; +double grow_factor; +int reorder_flag; +{ + int i; + st_table *new; + + new = ALLOC(st_table, 1); + if (new == NULL) { + return NULL; + } + new->compare = compare; + new->hash = hash; + new->num_entries = 0; + new->max_density = density; + new->grow_factor = grow_factor; + new->reorder_flag = reorder_flag; + if (size <= 0) { + size = 1; + } + new->num_bins = size; + new->bins = ALLOC(st_table_entry *, size); + if (new->bins == NULL) { + FREE(new); + return NULL; + } + for(i = 0; i < size; i++) { + new->bins[i] = 0; + } + return new; +} + +st_table * +st_init_table(compare, hash) +int (*compare)(); +int (*hash)(); +{ + return st_init_table_with_params(compare, hash, ST_DEFAULT_INIT_TABLE_SIZE, + ST_DEFAULT_MAX_DENSITY, + ST_DEFAULT_GROW_FACTOR, + ST_DEFAULT_REORDER_FLAG); +} + +void +st_free_table(table) +st_table *table; +{ + register st_table_entry *ptr, *next; + int i; + + for(i = 0; i < table->num_bins ; i++) { + ptr = table->bins[i]; + while (ptr != NULL) { + next = ptr->next; + FREE(ptr); + ptr = next; + } + } + FREE(table->bins); + FREE(table); +} + +#define PTR_NOT_EQUAL(table, ptr, user_key)\ +(ptr != NULL && !EQUAL(table->compare, user_key, (ptr)->key)) + +#define FIND_ENTRY(table, hash_val, key, ptr, last) \ + (last) = &(table)->bins[hash_val];\ + (ptr) = *(last);\ + while (PTR_NOT_EQUAL((table), (ptr), (key))) {\ + (last) = &(ptr)->next; (ptr) = *(last);\ + }\ + if ((ptr) != NULL && (table)->reorder_flag) {\ + *(last) = (ptr)->next;\ + (ptr)->next = (table)->bins[hash_val];\ + (table)->bins[hash_val] = (ptr);\ + } + +int +st_lookup(table, key, value) +st_table *table; +register char *key; +char **value; +{ + int hash_val; + register st_table_entry *ptr, **last; + + hash_val = do_hash(key, table); + + FIND_ENTRY(table, hash_val, key, ptr, last); + + if (ptr == NULL) { + return 0; + } else { + if (value != NULL) { + *value = ptr->record; + } + return 1; + } +} + +int +st_lookup_int(table, key, value) +st_table *table; +register char *key; +int *value; +{ + int hash_val; + register st_table_entry *ptr, **last; + + hash_val = do_hash(key, table); + + FIND_ENTRY(table, hash_val, key, ptr, last); + + if (ptr == NULL) { + return 0; + } else { + if (value != 0) { + *value = (long) ptr->record; + } + return 1; + } +} + +/* This macro does not check if memory allocation fails. Use at you own risk */ +#define ADD_DIRECT(table, key, value, hash_val, new)\ +{\ + if (table->num_entries/table->num_bins >= table->max_density) {\ + rehash(table);\ + hash_val = do_hash(key,table);\ + }\ + \ + new = ALLOC(st_table_entry, 1);\ + \ + new->key = key;\ + new->record = value;\ + new->next = table->bins[hash_val];\ + table->bins[hash_val] = new;\ + table->num_entries++;\ +} + +int +st_insert(table, key, value) +register st_table *table; +register char *key; +char *value; +{ + int hash_val; + st_table_entry *new; + register st_table_entry *ptr, **last; + + hash_val = do_hash(key, table); + + FIND_ENTRY(table, hash_val, key, ptr, last); + + if (ptr == NULL) { + if (table->num_entries/table->num_bins >= table->max_density) { + if (rehash(table) == ST_OUT_OF_MEM) { + return ST_OUT_OF_MEM; + } + hash_val = do_hash(key, table); + } + new = ALLOC(st_table_entry, 1); + if (new == NULL) { + return ST_OUT_OF_MEM; + } + new->key = key; + new->record = value; + new->next = table->bins[hash_val]; + table->bins[hash_val] = new; + table->num_entries++; + return 0; + } else { + ptr->record = value; + return 1; + } +} + +int +st_add_direct(table, key, value) +st_table *table; +char *key; +char *value; +{ + int hash_val; + st_table_entry *new; + + hash_val = do_hash(key, table); + if (table->num_entries / table->num_bins >= table->max_density) { + if (rehash(table) == ST_OUT_OF_MEM) { + return ST_OUT_OF_MEM; + } + } + hash_val = do_hash(key, table); + new = ALLOC(st_table_entry, 1); + if (new == NULL) { + return ST_OUT_OF_MEM; + } + new->key = key; + new->record = value; + new->next = table->bins[hash_val]; + table->bins[hash_val] = new; + table->num_entries++; + return 1; +} + +int +st_find_or_add(table, key, slot) +st_table *table; +char *key; +char ***slot; +{ + int hash_val; + st_table_entry *new, *ptr, **last; + + hash_val = do_hash(key, table); + + FIND_ENTRY(table, hash_val, key, ptr, last); + + if (ptr == NULL) { + if (table->num_entries / table->num_bins >= table->max_density) { + if (rehash(table) == ST_OUT_OF_MEM) { + return ST_OUT_OF_MEM; + } + hash_val = do_hash(key, table); + } + new = ALLOC(st_table_entry, 1); + if (new == NULL) { + return ST_OUT_OF_MEM; + } + new->key = key; + new->record = (char *) 0; + new->next = table->bins[hash_val]; + table->bins[hash_val] = new; + table->num_entries++; + if (slot != NULL) *slot = &new->record; + return 0; + } else { + if (slot != NULL) *slot = &ptr->record; + return 1; + } +} + +int +st_find(table, key, slot) +st_table *table; +char *key; +char ***slot; +{ + int hash_val; + st_table_entry *ptr, **last; + + hash_val = do_hash(key, table); + + FIND_ENTRY(table, hash_val, key, ptr, last); + + if (ptr == NULL) { + return 0; + } else { + if (slot != NULL) { + *slot = &ptr->record; + } + return 1; + } +} + +static int +rehash(table) +register st_table *table; +{ + register st_table_entry *ptr, *next, **old_bins; + int i, old_num_bins, hash_val, old_num_entries; + + /* save old values */ + old_bins = table->bins; + old_num_bins = table->num_bins; + old_num_entries = table->num_entries; + + /* rehash */ + table->num_bins = (int)(table->grow_factor * old_num_bins); + if (table->num_bins % 2 == 0) { + table->num_bins += 1; + } + table->num_entries = 0; + table->bins = ALLOC(st_table_entry *, table->num_bins); + if (table->bins == NULL) { + table->bins = old_bins; + table->num_bins = old_num_bins; + table->num_entries = old_num_entries; + return ST_OUT_OF_MEM; + } + /* initialize */ + for (i = 0; i < table->num_bins; i++) { + table->bins[i] = 0; + } + + /* copy data over */ + for (i = 0; i < old_num_bins; i++) { + ptr = old_bins[i]; + while (ptr != NULL) { + next = ptr->next; + hash_val = do_hash(ptr->key, table); + ptr->next = table->bins[hash_val]; + table->bins[hash_val] = ptr; + table->num_entries++; + ptr = next; + } + } + FREE(old_bins); + + return 1; +} + +st_table * +st_copy(old_table) +st_table *old_table; +{ + st_table *new_table; + st_table_entry *ptr, *newptr, *next, *new; + int i, j, num_bins = old_table->num_bins; + + new_table = ALLOC(st_table, 1); + if (new_table == NULL) { + return NULL; + } + + *new_table = *old_table; + new_table->bins = ALLOC(st_table_entry *, num_bins); + if (new_table->bins == NULL) { + FREE(new_table); + return NULL; + } + for(i = 0; i < num_bins ; i++) { + new_table->bins[i] = NULL; + ptr = old_table->bins[i]; + while (ptr != NULL) { + new = ALLOC(st_table_entry, 1); + if (new == NULL) { + for (j = 0; j <= i; j++) { + newptr = new_table->bins[j]; + while (newptr != NULL) { + next = newptr->next; + FREE(newptr); + newptr = next; + } + } + FREE(new_table->bins); + FREE(new_table); + return NULL; + } + *new = *ptr; + new->next = new_table->bins[i]; + new_table->bins[i] = new; + ptr = ptr->next; + } + } + return new_table; +} + +int +st_delete(table, keyp, value) +register st_table *table; +register char **keyp; +char **value; +{ + int hash_val; + char *key = *keyp; + register st_table_entry *ptr, **last; + + hash_val = do_hash(key, table); + + FIND_ENTRY(table, hash_val, key, ptr ,last); + + if (ptr == NULL) { + return 0; + } + + *last = ptr->next; + if (value != NULL) *value = ptr->record; + *keyp = ptr->key; + FREE(ptr); + table->num_entries--; + return 1; +} + +int +st_delete_int(table, keyp, value) +register st_table *table; +register long *keyp; +char **value; +{ + int hash_val; + char *key = (char *) *keyp; + register st_table_entry *ptr, **last; + + hash_val = do_hash(key, table); + + FIND_ENTRY(table, hash_val, key, ptr ,last); + + if (ptr == NULL) { + return 0; + } + + *last = ptr->next; + if (value != NULL) *value = ptr->record; + *keyp = (long) ptr->key; + FREE(ptr); + table->num_entries--; + return 1; +} + +int +st_foreach(table, func, arg) +st_table *table; +enum st_retval (*func)(); +char *arg; +{ + st_table_entry *ptr, **last; + enum st_retval retval; + int i; + + for(i = 0; i < table->num_bins; i++) { + last = &table->bins[i]; ptr = *last; + while (ptr != NULL) { + retval = (*func)(ptr->key, ptr->record, arg); + switch (retval) { + case ST_CONTINUE: + last = &ptr->next; ptr = *last; + break; + case ST_STOP: + return 0; + case ST_DELETE: + *last = ptr->next; + table->num_entries--; /* cstevens@ic */ + FREE(ptr); + ptr = *last; + } + } + } + return 1; +} + +int +st_strhash(string, modulus) +register char *string; +int modulus; +{ + register int val = 0; + register int c; + + while ((c = *string++) != '\0') { + val = val*997 + c; + } + + return ((val < 0) ? -val : val)%modulus; +} + +int +st_numhash(x, size) +char *x; +int size; +{ + return ST_NUMHASH(x, size); +} + +int +st_ptrhash(x, size) +char *x; +int size; +{ + return ST_PTRHASH(x, size); +} + +int +st_numcmp(x, y) +char *x; +char *y; +{ + return ST_NUMCMP(x, y); +} + +int +st_ptrcmp(x, y) +char *x; +char *y; +{ + return ST_NUMCMP(x, y); +} + +st_generator * +st_init_gen(table) +st_table *table; +{ + st_generator *gen; + + gen = ALLOC(st_generator, 1); + if (gen == NULL) { + return NULL; + } + gen->table = table; + gen->entry = NULL; + gen->index = 0; + return gen; +} + + +int +st_gen(gen, key_p, value_p) +st_generator *gen; +char **key_p; +char **value_p; +{ + register int i; + + if (gen->entry == NULL) { + /* try to find next entry */ + for(i = gen->index; i < gen->table->num_bins; i++) { + if (gen->table->bins[i] != NULL) { + gen->index = i+1; + gen->entry = gen->table->bins[i]; + break; + } + } + if (gen->entry == NULL) { + return 0; /* that's all folks ! */ + } + } + *key_p = gen->entry->key; + if (value_p != 0) { + *value_p = gen->entry->record; + } + gen->entry = gen->entry->next; + return 1; +} + + +int +st_gen_int(gen, key_p, value_p) +st_generator *gen; +char **key_p; +long *value_p; +{ + register int i; + + if (gen->entry == NULL) { + /* try to find next entry */ + for(i = gen->index; i < gen->table->num_bins; i++) { + if (gen->table->bins[i] != NULL) { + gen->index = i+1; + gen->entry = gen->table->bins[i]; + break; + } + } + if (gen->entry == NULL) { + return 0; /* that's all folks ! */ + } + } + *key_p = gen->entry->key; + if (value_p != 0) { + *value_p = (long) gen->entry->record; + } + gen->entry = gen->entry->next; + return 1; +} + + +void +st_free_gen(gen) +st_generator *gen; +{ + FREE(gen); +} diff --git a/src/misc/st/st.h b/src/misc/st/st.h new file mode 100644 index 00000000..b15f3c83 --- /dev/null +++ b/src/misc/st/st.h @@ -0,0 +1,96 @@ +/* + * Revision Control Information + * + * /projects/hsis/CVS/utilities/st/st.h,v + * serdar + * 1.1 + * 1993/07/29 01:00:21 + * + */ +/* LINTLIBRARY */ + +/* /projects/hsis/CVS/utilities/st/st.h,v 1.1 1993/07/29 01:00:21 serdar Exp */ + +#ifndef ST_INCLUDED +#define ST_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct st_table_entry st_table_entry; +struct st_table_entry { + char *key; + char *record; + st_table_entry *next; +}; + +typedef struct st_table st_table; +struct st_table { + int (*compare)(); + int (*hash)(); + int num_bins; + int num_entries; + int max_density; + int reorder_flag; + double grow_factor; + st_table_entry **bins; +}; + +typedef struct st_generator st_generator; +struct st_generator { + st_table *table; + st_table_entry *entry; + int index; +}; + +#define st_is_member(table,key) st_lookup(table,key,(char **) 0) +#define st_count(table) ((table)->num_entries) + +enum st_retval {ST_CONTINUE, ST_STOP, ST_DELETE}; + +typedef enum st_retval (*ST_PFSR)(); +typedef int (*ST_PFI)(); + +extern st_table *st_init_table_with_params (ST_PFI, ST_PFI, int, int, double, int); +extern st_table *st_init_table (ST_PFI, ST_PFI); +extern void st_free_table (st_table *); +extern int st_lookup (st_table *, char *, char **); +extern int st_lookup_int (st_table *, char *, int *); +extern int st_insert (st_table *, char *, char *); +extern int st_add_direct (st_table *, char *, char *); +extern int st_find_or_add (st_table *, char *, char ***); +extern int st_find (st_table *, char *, char ***); +extern st_table *st_copy (st_table *); +extern int st_delete (st_table *, char **, char **); +extern int st_delete_int (st_table *, long *, char **); +extern int st_foreach (st_table *, ST_PFSR, char *); +extern int st_strhash (char *, int); +extern int st_numhash (char *, int); +extern int st_ptrhash (char *, int); +extern int st_numcmp (char *, char *); +extern int st_ptrcmp (char *, char *); +extern st_generator *st_init_gen (st_table *); +extern int st_gen (st_generator *, char **, char **); +extern int st_gen_int (st_generator *, char **, long *); +extern void st_free_gen (st_generator *); + + +#define ST_DEFAULT_MAX_DENSITY 5 +#define ST_DEFAULT_INIT_TABLE_SIZE 11 +#define ST_DEFAULT_GROW_FACTOR 2.0 +#define ST_DEFAULT_REORDER_FLAG 0 + +#define st_foreach_item(table, gen, key, value) \ + for(gen=st_init_gen(table); st_gen(gen,key,value) || (st_free_gen(gen),0);) + +#define st_foreach_item_int(table, gen, key, value) \ + for(gen=st_init_gen(table); st_gen_int(gen,key,value) || (st_free_gen(gen),0);) + +#define ST_OUT_OF_MEM -10000 + +#ifdef __cplusplus +} +#endif + +#endif /* ST_INCLUDED */ diff --git a/src/misc/st/stmm.c b/src/misc/st/stmm.c new file mode 100644 index 00000000..8dfacfe4 --- /dev/null +++ b/src/misc/st/stmm.c @@ -0,0 +1,688 @@ +/* + * Revision Control Information + * + * /projects/hsis/CVS/utilities/st/st.c,v + * serdar + * 1.1 + * 1993/07/29 01:00:13 + * + */ +#include +#include "extra.h" +#include "stmm.h" + +#ifndef ABS +# define ABS(a) ((a) < 0 ? -(a) : (a)) +#endif + +#define STMM_NUMCMP(x,y) ((x) != (y)) +#define STMM_NUMHASH(x,size) (ABS((long)x)%(size)) +//#define STMM_PTRHASH(x,size) ((int)((unsigned long)(x)>>2)%size) // 64-bit bug fix 9/17/2007 +#define STMM_PTRHASH(x,size) ((int)(((unsigned long)(x)>>2)%size)) +#define EQUAL(func, x, y) \ + ((((func) == stmm_numcmp) || ((func) == stmm_ptrcmp)) ?\ + (STMM_NUMCMP((x),(y)) == 0) : ((*func)((x), (y)) == 0)) + + +#define do_hash(key, table)\ + ((table->hash == stmm_ptrhash) ? STMM_PTRHASH((key),(table)->num_bins) :\ + (table->hash == stmm_numhash) ? STMM_NUMHASH((key), (table)->num_bins) :\ + (*table->hash)((key), (table)->num_bins)) + +static int rehash (); +int stmm_numhash (), stmm_ptrhash (), stmm_numcmp (), stmm_ptrcmp (); + +stmm_table * +stmm_init_table_with_params (compare, hash, size, density, grow_factor, + reorder_flag) + int (*compare) (); + int (*hash) (); + int size; + int density; + double grow_factor; + int reorder_flag; +{ + int i; + stmm_table *new; + + new = ALLOC (stmm_table, 1); + if (new == NULL) { + return NULL; + } + new->compare = compare; + new->hash = hash; + new->num_entries = 0; + new->max_density = density; + new->grow_factor = grow_factor; + new->reorder_flag = reorder_flag; + if (size <= 0) { + size = 1; + } + new->num_bins = size; + new->bins = ALLOC (stmm_table_entry *, size); + if (new->bins == NULL) { + FREE (new); + return NULL; + } + for (i = 0; i < size; i++) { + new->bins[i] = 0; + } + + // added by alanmi + new->pMemMan = Extra_MmFixedStart(sizeof (stmm_table_entry)); + return new; +} + +stmm_table * +stmm_init_table (compare, hash) + int (*compare) (); + int (*hash) (); +{ + return stmm_init_table_with_params (compare, hash, + STMM_DEFAULT_INIT_TABLE_SIZE, + STMM_DEFAULT_MAX_DENSITY, + STMM_DEFAULT_GROW_FACTOR, + STMM_DEFAULT_REORDER_FLAG); +} + +void +stmm_free_table (table) + stmm_table *table; +{ +/* + register stmm_table_entry *ptr, *next; + int i; + for ( i = 0; i < table->num_bins; i++ ) + { + ptr = table->bins[i]; + while ( ptr != NULL ) + { + next = ptr->next; + FREE( ptr ); + ptr = next; + } + } +*/ + // no need to deallocate entries because they are in the memory manager now + // added by alanmi + if ( table->pMemMan ) + Extra_MmFixedStop (table->pMemMan); + FREE (table->bins); + FREE (table); +} + +// this function recycles all the bins +void +stmm_clean (table) + stmm_table *table; +{ + int i; + // clean the bins + for (i = 0; i < table->num_bins; i++) + table->bins[i] = NULL; + // reset the parameters + table->num_entries = 0; + // restart the memory manager + Extra_MmFixedRestart (table->pMemMan); +} + + +#define PTR_NOT_EQUAL(table, ptr, user_key)\ +(ptr != NULL && !EQUAL(table->compare, user_key, (ptr)->key)) + +#define FIND_ENTRY(table, hash_val, key, ptr, last) \ + (last) = &(table)->bins[hash_val];\ + (ptr) = *(last);\ + while (PTR_NOT_EQUAL((table), (ptr), (key))) {\ + (last) = &(ptr)->next; (ptr) = *(last);\ + }\ + if ((ptr) != NULL && (table)->reorder_flag) {\ + *(last) = (ptr)->next;\ + (ptr)->next = (table)->bins[hash_val];\ + (table)->bins[hash_val] = (ptr);\ + } + +int +stmm_lookup (table, key, value) + stmm_table *table; + register char *key; + char **value; +{ + int hash_val; + register stmm_table_entry *ptr, **last; + + hash_val = do_hash (key, table); + + FIND_ENTRY (table, hash_val, key, ptr, last); + + if (ptr == NULL) { + return 0; + } + else { + if (value != NULL) + { + *value = ptr->record; + } + return 1; + } +} + +int +stmm_lookup_int (table, key, value) + stmm_table *table; + register char *key; + int *value; +{ + int hash_val; + register stmm_table_entry *ptr, **last; + + hash_val = do_hash (key, table); + + FIND_ENTRY (table, hash_val, key, ptr, last); + + if (ptr == NULL) { + return 0; + } + else { + if (value != 0) + { + *value = (long) ptr->record; + } + return 1; + } +} + +// This macro contained a line +// new = ALLOC(stmm_table_entry, 1); +// which was modified by alanmi + + +/* This macro does not check if memory allocation fails. Use at you own risk */ +#define ADD_DIRECT(table, key, value, hash_val, new)\ +{\ + if (table->num_entries/table->num_bins >= table->max_density) {\ + rehash(table);\ + hash_val = do_hash(key,table);\ + }\ + \ + new = (stmm_table_entry *)Extra_MmFixedEntryFetch( table->pMemMan );\ + \ + new->key = key;\ + new->record = value;\ + new->next = table->bins[hash_val];\ + table->bins[hash_val] = new;\ + table->num_entries++;\ +} + +int +stmm_insert (table, key, value) + register stmm_table *table; + register char *key; + char *value; +{ + int hash_val; + stmm_table_entry *new; + register stmm_table_entry *ptr, **last; + + hash_val = do_hash (key, table); + + FIND_ENTRY (table, hash_val, key, ptr, last); + + if (ptr == NULL) { + if (table->num_entries / table->num_bins >= table->max_density) { + if (rehash (table) == STMM_OUT_OF_MEM) { + return STMM_OUT_OF_MEM; + } + hash_val = do_hash (key, table); + } + +// new = ALLOC( stmm_table_entry, 1 ); + new = (stmm_table_entry *) Extra_MmFixedEntryFetch (table->pMemMan); + if (new == NULL) { + return STMM_OUT_OF_MEM; + } + + new->key = key; + new->record = value; + new->next = table->bins[hash_val]; + table->bins[hash_val] = new; + table->num_entries++; + return 0; + } + else { + ptr->record = value; + return 1; + } +} + +int +stmm_add_direct (table, key, value) + stmm_table *table; + char *key; + char *value; +{ + int hash_val; + stmm_table_entry *new; + + hash_val = do_hash (key, table); + if (table->num_entries / table->num_bins >= table->max_density) { + if (rehash (table) == STMM_OUT_OF_MEM) { + return STMM_OUT_OF_MEM; + } + } + hash_val = do_hash (key, table); + +// new = ALLOC( stmm_table_entry, 1 ); + new = (stmm_table_entry *) Extra_MmFixedEntryFetch (table->pMemMan); + if (new == NULL) { + return STMM_OUT_OF_MEM; + } + + new->key = key; + new->record = value; + new->next = table->bins[hash_val]; + table->bins[hash_val] = new; + table->num_entries++; + return 1; +} + +int +stmm_find_or_add (table, key, slot) + stmm_table *table; + char *key; + char ***slot; +{ + int hash_val; + stmm_table_entry *new, *ptr, **last; + + hash_val = do_hash (key, table); + + FIND_ENTRY (table, hash_val, key, ptr, last); + + if (ptr == NULL) { + if (table->num_entries / table->num_bins >= table->max_density) { + if (rehash (table) == STMM_OUT_OF_MEM) { + return STMM_OUT_OF_MEM; + } + hash_val = do_hash (key, table); + } + + // new = ALLOC( stmm_table_entry, 1 ); + new = (stmm_table_entry *) Extra_MmFixedEntryFetch (table->pMemMan); + if (new == NULL) { + return STMM_OUT_OF_MEM; + } + + new->key = key; + new->record = (char *) 0; + new->next = table->bins[hash_val]; + table->bins[hash_val] = new; + table->num_entries++; + if (slot != NULL) + *slot = &new->record; + return 0; + } + else { + if (slot != NULL) + *slot = &ptr->record; + return 1; + } +} + +int +stmm_find (table, key, slot) + stmm_table *table; + char *key; + char ***slot; +{ + int hash_val; + stmm_table_entry *ptr, **last; + + hash_val = do_hash (key, table); + + FIND_ENTRY (table, hash_val, key, ptr, last); + + if (ptr == NULL) { + return 0; + } + else { + if (slot != NULL) + { + *slot = &ptr->record; + } + return 1; + } +} + +static int +rehash (table) + register stmm_table *table; +{ + register stmm_table_entry *ptr, *next, **old_bins; + int i, old_num_bins, hash_val, old_num_entries; + + /* save old values */ + old_bins = table->bins; + old_num_bins = table->num_bins; + old_num_entries = table->num_entries; + + /* rehash */ + table->num_bins = (int) (table->grow_factor * old_num_bins); + if (table->num_bins % 2 == 0) { + table->num_bins += 1; + } + table->num_entries = 0; + table->bins = ALLOC (stmm_table_entry *, table->num_bins); + if (table->bins == NULL) { + table->bins = old_bins; + table->num_bins = old_num_bins; + table->num_entries = old_num_entries; + return STMM_OUT_OF_MEM; + } + /* initialize */ + for (i = 0; i < table->num_bins; i++) { + table->bins[i] = 0; + } + + /* copy data over */ + for (i = 0; i < old_num_bins; i++) { + ptr = old_bins[i]; + while (ptr != NULL) { + next = ptr->next; + hash_val = do_hash (ptr->key, table); + ptr->next = table->bins[hash_val]; + table->bins[hash_val] = ptr; + table->num_entries++; + ptr = next; + } + } + FREE (old_bins); + + return 1; +} + +stmm_table * +stmm_copy (old_table) + stmm_table *old_table; +{ + stmm_table *new_table; + stmm_table_entry *ptr, /* *newptr, *next, */ *new; + int i, /*j, */ num_bins = old_table->num_bins; + + new_table = ALLOC (stmm_table, 1); + if (new_table == NULL) { + return NULL; + } + + *new_table = *old_table; + new_table->bins = ALLOC (stmm_table_entry *, num_bins); + if (new_table->bins == NULL) { + FREE (new_table); + return NULL; + } + + // allocate the memory manager for the new table + new_table->pMemMan = + Extra_MmFixedStart (sizeof (stmm_table_entry)); + + for (i = 0; i < num_bins; i++) { + new_table->bins[i] = NULL; + ptr = old_table->bins[i]; + while (ptr != NULL) { +// new = ALLOC( stmm_table_entry, 1 ); + new = + (stmm_table_entry *) Extra_MmFixedEntryFetch (new_table-> + pMemMan); + + if (new == NULL) { +/* + for ( j = 0; j <= i; j++ ) + { + newptr = new_table->bins[j]; + while ( newptr != NULL ) + { + next = newptr->next; + FREE( newptr ); + newptr = next; + } + } +*/ + Extra_MmFixedStop (new_table->pMemMan); + + FREE (new_table->bins); + FREE (new_table); + return NULL; + } + *new = *ptr; + new->next = new_table->bins[i]; + new_table->bins[i] = new; + ptr = ptr->next; + } + } + return new_table; +} + +int +stmm_delete (table, keyp, value) + register stmm_table *table; + register char **keyp; + char **value; +{ + int hash_val; + char *key = *keyp; + register stmm_table_entry *ptr, **last; + + hash_val = do_hash (key, table); + + FIND_ENTRY (table, hash_val, key, ptr, last); + + if (ptr == NULL) { + return 0; + } + + *last = ptr->next; + if (value != NULL) + *value = ptr->record; + *keyp = ptr->key; +// FREE( ptr ); + Extra_MmFixedEntryRecycle (table->pMemMan, (char *) ptr); + + table->num_entries--; + return 1; +} + +int +stmm_delete_int (table, keyp, value) + register stmm_table *table; + register long *keyp; + char **value; +{ + int hash_val; + char *key = (char *) *keyp; + register stmm_table_entry *ptr, **last; + + hash_val = do_hash (key, table); + + FIND_ENTRY (table, hash_val, key, ptr, last); + + if (ptr == NULL) { + return 0; + } + + *last = ptr->next; + if (value != NULL) + *value = ptr->record; + *keyp = (long) ptr->key; +// FREE( ptr ); + Extra_MmFixedEntryRecycle (table->pMemMan, (char *) ptr); + + table->num_entries--; + return 1; +} + +int +stmm_foreach (table, func, arg) + stmm_table *table; + enum stmm_retval (*func) (); + char *arg; +{ + stmm_table_entry *ptr, **last; + enum stmm_retval retval; + int i; + + for (i = 0; i < table->num_bins; i++) { + last = &table->bins[i]; + ptr = *last; + while (ptr != NULL) { + retval = (*func) (ptr->key, ptr->record, arg); + switch (retval) { + case STMM_CONTINUE: + last = &ptr->next; + ptr = *last; + break; + case STMM_STOP: + return 0; + case STMM_DELETE: + *last = ptr->next; + table->num_entries--; /* cstevens@ic */ +// FREE( ptr ); + Extra_MmFixedEntryRecycle (table->pMemMan, (char *) ptr); + + ptr = *last; + } + } + } + return 1; +} + +int +stmm_strhash (string, modulus) + register char *string; + int modulus; +{ + register int val = 0; + register int c; + + while ((c = *string++) != '\0') { + val = val * 997 + c; + } + + return ((val < 0) ? -val : val) % modulus; +} + +int +stmm_numhash (x, size) + char *x; + int size; +{ + return STMM_NUMHASH (x, size); +} + +int +stmm_ptrhash (x, size) + char *x; + int size; +{ + return STMM_PTRHASH (x, size); +} + +int +stmm_numcmp (x, y) + char *x; + char *y; +{ + return STMM_NUMCMP (x, y); +} + +int +stmm_ptrcmp (x, y) + char *x; + char *y; +{ + return STMM_NUMCMP (x, y); +} + +stmm_generator * +stmm_init_gen (table) + stmm_table *table; +{ + stmm_generator *gen; + + gen = ALLOC (stmm_generator, 1); + if (gen == NULL) { + return NULL; + } + gen->table = table; + gen->entry = NULL; + gen->index = 0; + return gen; +} + + +int +stmm_gen (gen, key_p, value_p) + stmm_generator *gen; + char **key_p; + char **value_p; +{ + register int i; + + if (gen->entry == NULL) { + /* try to find next entry */ + for (i = gen->index; i < gen->table->num_bins; i++) { + if (gen->table->bins[i] != NULL) { + gen->index = i + 1; + gen->entry = gen->table->bins[i]; + break; + } + } + if (gen->entry == NULL) { + return 0; /* that's all folks ! */ + } + } + *key_p = gen->entry->key; + if (value_p != 0) { + *value_p = gen->entry->record; + } + gen->entry = gen->entry->next; + return 1; +} + + +int +stmm_gen_int (gen, key_p, value_p) + stmm_generator *gen; + char **key_p; + long *value_p; +{ + register int i; + + if (gen->entry == NULL) { + /* try to find next entry */ + for (i = gen->index; i < gen->table->num_bins; i++) { + if (gen->table->bins[i] != NULL) { + gen->index = i + 1; + gen->entry = gen->table->bins[i]; + break; + } + } + if (gen->entry == NULL) { + return 0; /* that's all folks ! */ + } + } + *key_p = gen->entry->key; + if (value_p != 0) + { + *value_p = (long) gen->entry->record; + } + gen->entry = gen->entry->next; + return 1; +} + + +void +stmm_free_gen (gen) + stmm_generator *gen; +{ + FREE (gen); +} diff --git a/src/misc/st/stmm.h b/src/misc/st/stmm.h new file mode 100644 index 00000000..4330416e --- /dev/null +++ b/src/misc/st/stmm.h @@ -0,0 +1,127 @@ +/* + * Revision Control Information + * + * /projects/hsis/CVS/utilities/st/st.h,v + * serdar + * 1.1 + * 1993/07/29 01:00:21 + * + */ +/* LINTLIBRARY */ + +/* /projects/hsis/CVS/utilities/st/st.h,v 1.1 1993/07/29 01:00:21 serdar Exp */ + +#ifndef STMM_INCLUDED +#define STMM_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +#include "extra.h" + +typedef struct stmm_table_entry stmm_table_entry; +typedef struct stmm_table stmm_table; +typedef struct stmm_generator stmm_generator; + +struct stmm_table_entry +{ + char *key; + char *record; + stmm_table_entry *next; +}; + +struct stmm_table +{ + int (*compare) (); + int (*hash) (); + int num_bins; + int num_entries; + int max_density; + int reorder_flag; + double grow_factor; + stmm_table_entry **bins; + // memory manager to improve runtime and prevent memory fragmentation + // added by alanmi - January 16, 2003 + Extra_MmFixed_t *pMemMan; +}; + +struct stmm_generator +{ + stmm_table *table; + stmm_table_entry *entry; + int index; +}; + +#define stmm_is_member(table,key) stmm_lookup(table,key,(char **) 0) +#define stmm_count(table) ((table)->num_entries) + +enum stmm_retval +{ STMM_CONTINUE, STMM_STOP, STMM_DELETE }; + +typedef enum stmm_retval (*STMM_PFSR) (); +typedef int (*STMM_PFI) (); + +EXTERN stmm_table *stmm_init_table_with_params +ARGS ((STMM_PFI, STMM_PFI, int, int, double, int)); +EXTERN stmm_table *stmm_init_table ARGS ((STMM_PFI, STMM_PFI)); +EXTERN void stmm_free_table ARGS ((stmm_table *)); +EXTERN int stmm_lookup ARGS ((stmm_table *, char *, char **)); +EXTERN int stmm_lookup_int ARGS ((stmm_table *, char *, int *)); +EXTERN int stmm_insert ARGS ((stmm_table *, char *, char *)); +EXTERN int stmm_add_direct ARGS ((stmm_table *, char *, char *)); +EXTERN int stmm_find_or_add ARGS ((stmm_table *, char *, char ***)); +EXTERN int stmm_find ARGS ((stmm_table *, char *, char ***)); +EXTERN stmm_table *stmm_copy ARGS ((stmm_table *)); +EXTERN int stmm_delete ARGS ((stmm_table *, char **, char **)); +EXTERN int stmm_delete_int ARGS ((stmm_table *, long *, char **)); +EXTERN int stmm_foreach ARGS ((stmm_table *, STMM_PFSR, char *)); +EXTERN int stmm_strhash ARGS ((char *, int)); +EXTERN int stmm_numhash ARGS ((char *, int)); +EXTERN int stmm_ptrhash ARGS ((char *, int)); +EXTERN int stmm_numcmp ARGS ((char *, char *)); +EXTERN int stmm_ptrcmp ARGS ((char *, char *)); +EXTERN stmm_generator *stmm_init_gen ARGS ((stmm_table *)); +EXTERN int stmm_gen ARGS ((stmm_generator *, char **, char **)); +EXTERN int stmm_gen_int ARGS ((stmm_generator *, char **, long *)); +EXTERN void stmm_free_gen ARGS ((stmm_generator *)); +// additional functions +EXTERN void stmm_clean ARGS ((stmm_table *)); + + + +#define STMM_DEFAULT_MAX_DENSITY 5 +#define STMM_DEFAULT_INIT_TABLE_SIZE 11 +#define STMM_DEFAULT_GROW_FACTOR 2.0 +#define STMM_DEFAULT_REORDER_FLAG 0 + +// added by Zhihong: no need for memory allocation +#define stmm_foreach_item2(tb, /* stmm_generator */gen, key, value) \ + for(gen.table=(tb), gen.entry=NULL, gen.index=0; \ + stmm_gen(&(gen),key,value);) + +#define stmm_foreach_item(table, gen, key, value) \ + for(gen=stmm_init_gen(table); stmm_gen(gen,key,value) || (stmm_free_gen(gen),0);) + +#define stmm_foreach_item_int(table, gen, key, value) \ + for(gen=stmm_init_gen(table); stmm_gen_int(gen,key,value) || (stmm_free_gen(gen),0);) + +#define STMM_OUT_OF_MEM -10000 + +/* + +// consider adding these other other similar definitions +#define st_table stmm_table +#define st_insert stmm_insert +#define st_delete stmm_delete +#define st_lookup stmm_lookup +#define st_init_table stmm_init_table +#define st_free_table stmm_free_table + +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* STMM_INCLUDED */ diff --git a/src/misc/util/leaks.h b/src/misc/util/leaks.h new file mode 100644 index 00000000..1a32062a --- /dev/null +++ b/src/misc/util/leaks.h @@ -0,0 +1,30 @@ +////////////////////////////////////////////////////////////////////////// +// This file is used to detect memory leaks using Visual Studio 6.0 +// The idea comes from this page: http://www.michaelmoser.org/memory.htm +// In addition to this file, it required the presence of "stdlib_hack.h" +////////////////////////////////////////////////////////////////////////// + +#ifndef __LEAKS_H__ +#define __LEAKS_H__ + +#ifdef _DEBUG +#define _CRTDBG_MAP_ALLOC // include Microsoft memory leak detection procedures +//#define _INC_MALLOC // exclude standard memory alloc procedures + +#define malloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__) +#define calloc(c, s) _calloc_dbg(c, s, _NORMAL_BLOCK, __FILE__, __LINE__) +#define realloc(p, s) _realloc_dbg(p, s, _NORMAL_BLOCK, __FILE__, __LINE__) +//#define _expand(p, s) _expand_dbg(p, s, _NORMAL_BLOCK, __FILE__, __LINE__) +//#define free(p) _free_dbg(p, _NORMAL_BLOCK) +//#define _msize(p) _msize_dbg(p, _NORMAL_BLOCK) + +//#include +#include +#include +#endif + +#endif + +////////////////////////////////////// + + diff --git a/src/misc/util/module.make b/src/misc/util/module.make new file mode 100644 index 00000000..d6d908e7 --- /dev/null +++ b/src/misc/util/module.make @@ -0,0 +1 @@ +SRC += diff --git a/src/misc/util/stdlib_hack.h b/src/misc/util/stdlib_hack.h new file mode 100644 index 00000000..2ddf73d1 --- /dev/null +++ b/src/misc/util/stdlib_hack.h @@ -0,0 +1,4 @@ + +#include + + diff --git a/src/misc/util/util_hack.h b/src/misc/util/util_hack.h new file mode 100644 index 00000000..71c77321 --- /dev/null +++ b/src/misc/util/util_hack.h @@ -0,0 +1,95 @@ +/**CFile**************************************************************** + + FileName [util_hack.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [This file is used to simulate the presence of "util.h".] + + Synopsis [External declarations.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: util_hack.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#ifndef __UTIL_HACK_H__ +#define __UTIL_HACK_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include +#include +#include + +#define EXTERN extern +#define NIL(type) ((type *) 0) +#define random rand +#define srandom srand + +#define util_cpu_time Extra_CpuTime +#define getSoftDataLimit Extra_GetSoftDataLimit +#define util_getopt_reset Extra_UtilGetoptReset +#define util_getopt Extra_UtilGetopt +#define util_print_time Extra_UtilPrintTime +#define util_strsav Extra_UtilStrsav +#define util_tilde_expand Extra_UtilTildeExpand +#define util_file_search Extra_UtilFileSearch +#define MMoutOfMemory Extra_UtilMMoutOfMemory + +#define util_optarg globalUtilOptarg +#define util_optind globalUtilOptind + +#ifndef ARGS +# ifdef __STDC__ +# define ARGS(args) args +# else +# define ARGS(args) () +# endif +#endif + +#ifndef ABS +# define ABS(a) ((a) < 0 ? -(a) : (a)) +#endif + +#ifndef MAX +# define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef MIN +# define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#define ALLOC(type, num) ((type *) malloc(sizeof(type) * (num))) +#define FREE(obj) ((obj) ? (free((char *) (obj)), (obj) = 0) : 0) +#define REALLOC(type, obj, num) \ + ((obj) ? ((type *) realloc((char *)(obj), sizeof(type) * (num))) : \ + ((type *) malloc(sizeof(type) * (num)))) + +extern long Extra_CpuTime(); +extern int Extra_GetSoftDataLimit(); +extern void Extra_UtilGetoptReset(); +extern int Extra_UtilGetopt( int argc, char *argv[], char *optstring ); +extern char * Extra_UtilPrintTime( long t ); +extern char * Extra_UtilStrsav( char *s ); +extern char * Extra_UtilTildeExpand( char *fname ); +extern char * Extra_UtilFileSearch( char *file, char *path, char *mode ); + +extern char * globalUtilOptarg; +extern int globalUtilOptind; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/misc/vec/module.make b/src/misc/vec/module.make new file mode 100644 index 00000000..d6d908e7 --- /dev/null +++ b/src/misc/vec/module.make @@ -0,0 +1 @@ +SRC += diff --git a/src/misc/vec/vec.h b/src/misc/vec/vec.h new file mode 100644 index 00000000..a4bd4771 --- /dev/null +++ b/src/misc/vec/vec.h @@ -0,0 +1,121 @@ +/**CFile**************************************************************** + + FileName [vec.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Resizable arrays.] + + Synopsis [External declarations.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: vec.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#ifndef __VEC_H__ +#define __VEC_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _WIN32 +#define inline __inline // compatible with MS VS 6.0 +#pragma warning(disable : 4152) // warning C4152: nonstandard extension, function/data pointer conversion in expression +#pragma warning(disable : 4244) // warning C4244: '+=' : conversion from 'int ' to 'unsigned short ', possible loss of data +#pragma warning(disable : 4514) // warning C4514: 'Vec_StrPop' : unreferenced inline function has been removed +#pragma warning(disable : 4710) // warning C4710: function 'Vec_PtrGrow' not inlined +#endif + +#ifndef SINT64 +#define SINT64 + +#ifdef _WIN32 +typedef signed __int64 sint64; // compatible with MS VS 6.0 +#else +typedef long long sint64; +#endif + +#endif + +//////////////////////////////////////////////////////////////////////// +/// INCLUDES /// +//////////////////////////////////////////////////////////////////////// + +// this include should be the first one in the list +// it is used to catch memory leaks on Windows +#include "leaks.h" + +//////////////////////////////////////////////////////////////////////// +/// MACRO DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +#ifndef ABS +#define ABS(a) ((a) < 0 ? -(a) : (a)) +#endif + +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef ALLOC +#define ALLOC(type, num) ((type *) malloc(sizeof(type) * (num))) +#endif + +#ifndef FREE +#define FREE(obj) ((obj) ? (free((char *) (obj)), (obj) = 0) : 0) +#endif + +#ifndef REALLOC +#define REALLOC(type, obj, num) \ + ((obj) ? ((type *) realloc((char *)(obj), sizeof(type) * (num))) : \ + ((type *) malloc(sizeof(type) * (num)))) +#endif + +#ifndef PRT +#define PRT(a,t) printf("%s = ", (a)); printf("%6.2f sec\n", (float)(t)/(float)(CLOCKS_PER_SEC)) +#endif + +#ifndef PRTP +#define PRTP(a,t,T) printf("%s = ", (a)); printf("%6.2f sec (%6.2f %%)\n", (float)(t)/(float)(CLOCKS_PER_SEC), (T)? 100.0*(t)/(T) : 0.0) +#endif + +#include "vecInt.h" +#include "vecFlt.h" +#include "vecStr.h" +#include "vecPtr.h" +#include "vecVec.h" +#include "vecAtt.h" + +//////////////////////////////////////////////////////////////////////// +/// PARAMETERS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// BASIC TYPES /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +#ifdef __cplusplus +} +#endif + +#endif + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + diff --git a/src/misc/vec/vecAtt.h b/src/misc/vec/vecAtt.h new file mode 100644 index 00000000..da7a8445 --- /dev/null +++ b/src/misc/vec/vecAtt.h @@ -0,0 +1,391 @@ +/**CFile**************************************************************** + + FileName [vecAtt.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Resizable arrays.] + + Synopsis [Array of user-specified attiributes.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: vecAtt.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#ifndef __Vec_Att_H__ +#define __Vec_Att_H__ + +//////////////////////////////////////////////////////////////////////// +/// INCLUDES /// +//////////////////////////////////////////////////////////////////////// + +#include + +//////////////////////////////////////////////////////////////////////// +/// PARAMETERS /// +//////////////////////////////////////////////////////////////////////// + +// various attributes +typedef enum { + VEC_ATTR_NONE = 0, // 0 + VEC_ATTR_COPY, // 1 + VEC_ATTR_LOCAL_AIG, // 2 + VEC_ATTR_LOCAL_SOP, // 3 + VEC_ATTR_LOCAL_BDD, // 4 + VEC_ATTR_GLOBAL_AIG, // 5 + VEC_ATTR_GLOBAL_SOP, // 6 + VEC_ATTR_GLOBAL_BDD, // 7 + VEC_ATTR_LEVEL, // 8 + VEC_ATTR_LEVEL_REV, // 9 + VEC_ATTR_RETIME_LAG, // 10 + VEC_ATTR_FRAIG, // 11 + VEC_ATTR_MVVAR, // 12 + VEC_ATTR_DATA1, // 13 + VEC_ATTR_DATA2, // 14 + VEC_ATTR_TOTAL_NUM // 15 +} Vec_AttrType_t; + +//////////////////////////////////////////////////////////////////////// +/// BASIC TYPES /// +//////////////////////////////////////////////////////////////////////// + +typedef struct Vec_Att_t_ Vec_Att_t; +struct Vec_Att_t_ +{ + // storage for attributes + int nCap; // the size of array allocated + int * pArrayInt; // the integer attribute array + void ** pArrayPtr; // the pointer attribute array + // attribute specific info + void * pMan; // the manager for this attribute + void (*pFuncFreeMan) (void *); // the procedure to free the manager + void*(*pFuncStartObj)(void *); // the procedure to start one attribute + void (*pFuncFreeObj) (void *, void *); // the procedure to free one attribute +}; + +//////////////////////////////////////////////////////////////////////// +/// MACRO DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Allocates a vector with the given capacity.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Att_t * Vec_AttAlloc( + int fInteger, int nSize, void * pMan, + void (*pFuncFreeMan) (void *), + void*(*pFuncStartObj)(void *), + void (*pFuncFreeObj) (void *, void *) ) +{ + Vec_Att_t * p; + p = ALLOC( Vec_Att_t, 1 ); + memset( p, 0, sizeof(Vec_Att_t) ); + p->pMan = pMan; + p->pFuncFreeMan = pFuncFreeMan; + p->pFuncStartObj = pFuncStartObj; + p->pFuncFreeObj = pFuncFreeObj; + p->nCap = nSize? nSize : 16; + if ( fInteger ) + { + p->pArrayInt = ALLOC( int, p->nCap ); + memset( p->pArrayInt, 0xff, sizeof(int) * p->nCap ); + } + else + { + p->pArrayPtr = ALLOC( void *, p->nCap ); + memset( p->pArrayPtr, 0, sizeof(void *) * p->nCap ); + } + return p; +} + +/**Function************************************************************* + + Synopsis [Frees the vector.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void * Vec_AttFree( Vec_Att_t * p, int fFreeMan ) +{ + void * pMan; + if ( p == NULL ) + return NULL; + // free the attributes of objects + if ( p->pFuncFreeObj ) + { + int i; + if ( p->pArrayInt ) + { + for ( i = 0; i < p->nCap; i++ ) + if ( p->pArrayInt[i] ) + p->pFuncFreeObj( p->pMan, (void *)p->pArrayInt[i] ); + } + else + { + for ( i = 0; i < p->nCap; i++ ) + if ( p->pArrayPtr[i] ) + p->pFuncFreeObj( p->pMan, p->pArrayPtr[i] ); + } + } + // free the memory manager + pMan = fFreeMan? NULL : p->pMan; + if ( p->pMan && fFreeMan ) + p->pFuncFreeMan( p->pMan ); + FREE( p->pArrayInt ); + FREE( p->pArrayPtr ); + FREE( p ); + return pMan; +} + +/**Function************************************************************* + + Synopsis [Clears the vector.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_AttClear( Vec_Att_t * p ) +{ + // free the attributes of objects + if ( p->pFuncFreeObj ) + { + int i; + if ( p->pArrayInt ) + { + if ( p->pFuncFreeObj ) + for ( i = 0; i < p->nCap; i++ ) + if ( p->pArrayInt[i] ) + p->pFuncFreeObj( p->pMan, (void *)p->pArrayInt[i] ); + } + else + { + if ( p->pFuncFreeObj ) + for ( i = 0; i < p->nCap; i++ ) + if ( p->pArrayPtr[i] ) + p->pFuncFreeObj( p->pMan, p->pArrayPtr[i] ); + } + } + if ( p->pArrayInt ) + memset( p->pArrayInt, 0xff, sizeof(int) * p->nCap ); + else + memset( p->pArrayPtr, 0, sizeof(void *) * p->nCap ); + +} + +/**Function************************************************************* + + Synopsis [Deletes one entry from the attribute manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_AttFreeEntry( Vec_Att_t * p, int i ) +{ + if ( i >= p->nCap ) + return; + if ( p->pMan ) + { + if ( p->pArrayInt[i] && p->pFuncFreeObj ) + p->pFuncFreeObj( p->pMan, (void *)p->pArrayInt[i] ); + if ( p->pArrayPtr[i] && p->pFuncFreeObj ) + p->pFuncFreeObj( p->pMan, (void *)p->pArrayPtr[i] ); + } + if ( p->pArrayInt ) + p->pArrayInt[i] = ~(unsigned)0; + else + p->pArrayPtr[i] = NULL; +} + +/**Function************************************************************* + + Synopsis [Resizes the vector to the given capacity.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_AttGrow( Vec_Att_t * p, int nCapMin ) +{ + if ( p->nCap >= nCapMin ) + return; + if ( p->pArrayInt ) + { + p->pArrayInt = REALLOC( int, p->pArrayInt, nCapMin ); + memset( p->pArrayInt + p->nCap, 0xff, sizeof(int) * (nCapMin - p->nCap) ); + } + else + { + p->pArrayPtr = REALLOC( void *, p->pArrayPtr, nCapMin ); + memset( p->pArrayPtr + p->nCap, 0, sizeof(void *) * (nCapMin - p->nCap) ); + } + p->nCap = nCapMin; +} + +/**Function************************************************************* + + Synopsis [Writes the entry into its place.] + + Description [Only works if the manager is not defined.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_AttWriteEntry( Vec_Att_t * p, int i, void * pEntry ) +{ + assert( p->pArrayPtr ); + assert( p->pFuncStartObj == NULL ); + if ( i >= p->nCap ) + Vec_AttGrow( p, (2 * p->nCap > i)? 2 * p->nCap : i + 10 ); + p->pArrayPtr[i] = pEntry; +} + +/**Function************************************************************* + + Synopsis [Writes the entry into its place.] + + Description [Only works if the manager is not defined.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_AttWriteEntryInt( Vec_Att_t * p, int i, int Entry ) +{ + assert( p->pArrayInt ); + assert( p->pFuncStartObj == NULL ); + if ( i >= p->nCap ) + Vec_AttGrow( p, (2 * p->nCap > i)? 2 * p->nCap : i + 10 ); + p->pArrayInt[i] = Entry; +} + +/**Function************************************************************* + + Synopsis [Returns the entry.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void * Vec_AttEntry( Vec_Att_t * p, int i ) +{ + assert( p->pArrayPtr ); + if ( i >= p->nCap ) + Vec_AttGrow( p, (2 * p->nCap > i)? 2 * p->nCap : i + 10 ); + if ( p->pArrayPtr[i] == NULL && p->pFuncStartObj ) + p->pArrayPtr[i] = p->pFuncStartObj( p->pMan ); + return p->pArrayPtr[i]; +} + +/**Function************************************************************* + + Synopsis [Returns the entry.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Vec_AttEntryInt( Vec_Att_t * p, int i ) +{ + assert( p->pArrayInt ); + assert( p->pMan == NULL ); + if ( i >= p->nCap ) + Vec_AttGrow( p, (2 * p->nCap > i)? 2 * p->nCap : i + 10 ); + return p->pArrayInt[i]; +} + +/**Function************************************************************* + + Synopsis [Returns the entry.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void * Vec_AttMan( Vec_Att_t * p ) +{ + return p->pMan; +} + +/**Function************************************************************* + + Synopsis [Returns the array of attributes.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void ** Vec_AttArray( Vec_Att_t * p ) +{ + return p->pArrayPtr; +} + +/**Function************************************************************* + + Synopsis [Returns the array of attributes.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int * Vec_AttArrayInt( Vec_Att_t * p ) +{ + return p->pArrayInt; +} + +#endif + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + diff --git a/src/misc/vec/vecFlt.h b/src/misc/vec/vecFlt.h new file mode 100644 index 00000000..6b36ce84 --- /dev/null +++ b/src/misc/vec/vecFlt.h @@ -0,0 +1,630 @@ +/**CFile**************************************************************** + + FileName [vecFlt.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Resizable arrays.] + + Synopsis [Resizable arrays of floats.] + + Author [Aaron P. Hurst] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: vecInt.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#ifndef __VEC_FLT_H__ +#define __VEC_FLT_H__ + +//////////////////////////////////////////////////////////////////////// +/// INCLUDES /// +//////////////////////////////////////////////////////////////////////// + +#include + +//////////////////////////////////////////////////////////////////////// +/// PARAMETERS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// BASIC TYPES /// +//////////////////////////////////////////////////////////////////////// + +typedef struct Vec_Flt_t_ Vec_Flt_t; +struct Vec_Flt_t_ +{ + int nCap; + int nSize; + float * pArray; +}; + +//////////////////////////////////////////////////////////////////////// +/// MACRO DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +#define Vec_FltForEachEntry( vVec, Entry, i ) \ + for ( i = 0; (i < Vec_FltSize(vVec)) && (((Entry) = Vec_FltEntry(vVec, i)), 1); i++ ) +#define Vec_FltForEachEntryStart( vVec, Entry, i, Start ) \ + for ( i = Start; (i < Vec_FltSize(vVec)) && (((Entry) = Vec_FltEntry(vVec, i)), 1); i++ ) +#define Vec_FltForEachEntryStartStop( vVec, Entry, i, Start, Stop ) \ + for ( i = Start; (i < Stop) && (((Entry) = Vec_FltEntry(vVec, i)), 1); i++ ) +#define Vec_FltForEachEntryReverse( vVec, pEntry, i ) \ + for ( i = Vec_FltSize(vVec) - 1; (i >= 0) && (((pEntry) = Vec_FltEntry(vVec, i)), 1); i-- ) + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Allocates a vector with the given capacity.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Flt_t * Vec_FltAlloc( int nCap ) +{ + Vec_Flt_t * p; + p = ALLOC( Vec_Flt_t, 1 ); + if ( nCap > 0 && nCap < 16 ) + nCap = 16; + p->nSize = 0; + p->nCap = nCap; + p->pArray = p->nCap? ALLOC( float, p->nCap ) : NULL; + return p; +} + +/**Function************************************************************* + + Synopsis [Allocates a vector with the given size and cleans it.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Flt_t * Vec_FltStart( int nSize ) +{ + Vec_Flt_t * p; + p = Vec_FltAlloc( nSize ); + p->nSize = nSize; + memset( p->pArray, 0, sizeof(float) * nSize ); + return p; +} + +/**Function************************************************************* + + Synopsis [Creates the vector from a float array of the given size.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Flt_t * Vec_FltAllocArray( float * pArray, int nSize ) +{ + Vec_Flt_t * p; + p = ALLOC( Vec_Flt_t, 1 ); + p->nSize = nSize; + p->nCap = nSize; + p->pArray = pArray; + return p; +} + +/**Function************************************************************* + + Synopsis [Creates the vector from a float array of the given size.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Flt_t * Vec_FltAllocArrayCopy( float * pArray, int nSize ) +{ + Vec_Flt_t * p; + p = ALLOC( Vec_Flt_t, 1 ); + p->nSize = nSize; + p->nCap = nSize; + p->pArray = ALLOC( float, nSize ); + memcpy( p->pArray, pArray, sizeof(float) * nSize ); + return p; +} + +/**Function************************************************************* + + Synopsis [Duplicates the float array.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Flt_t * Vec_FltDup( Vec_Flt_t * pVec ) +{ + Vec_Flt_t * p; + p = ALLOC( Vec_Flt_t, 1 ); + p->nSize = pVec->nSize; + p->nCap = pVec->nCap; + p->pArray = p->nCap? ALLOC( float, p->nCap ) : NULL; + memcpy( p->pArray, pVec->pArray, sizeof(float) * pVec->nSize ); + return p; +} + +/**Function************************************************************* + + Synopsis [Transfers the array into another vector.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Flt_t * Vec_FltDupArray( Vec_Flt_t * pVec ) +{ + Vec_Flt_t * p; + p = ALLOC( Vec_Flt_t, 1 ); + p->nSize = pVec->nSize; + p->nCap = pVec->nCap; + p->pArray = pVec->pArray; + pVec->nSize = 0; + pVec->nCap = 0; + pVec->pArray = NULL; + return p; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_FltFree( Vec_Flt_t * p ) +{ + FREE( p->pArray ); + FREE( p ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline float * Vec_FltReleaseArray( Vec_Flt_t * p ) +{ + float * pArray = p->pArray; + p->nCap = 0; + p->nSize = 0; + p->pArray = NULL; + return pArray; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline float * Vec_FltArray( Vec_Flt_t * p ) +{ + return p->pArray; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Vec_FltSize( Vec_Flt_t * p ) +{ + return p->nSize; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline float Vec_FltEntry( Vec_Flt_t * p, int i ) +{ + assert( i >= 0 && i < p->nSize ); + return p->pArray[i]; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_FltWriteEntry( Vec_Flt_t * p, int i, float Entry ) +{ + assert( i >= 0 && i < p->nSize ); + p->pArray[i] = Entry; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_FltAddToEntry( Vec_Flt_t * p, int i, float Addition ) +{ + assert( i >= 0 && i < p->nSize ); + p->pArray[i] += Addition; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline float Vec_FltEntryLast( Vec_Flt_t * p ) +{ + return p->pArray[p->nSize-1]; +} + +/**Function************************************************************* + + Synopsis [Resizes the vector to the given capacity.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_FltGrow( Vec_Flt_t * p, int nCapMin ) +{ + if ( p->nCap >= nCapMin ) + return; + p->pArray = REALLOC( float, p->pArray, nCapMin ); + p->nCap = nCapMin; +} + +/**Function************************************************************* + + Synopsis [Fills the vector with given number of entries.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_FltFill( Vec_Flt_t * p, int nSize, float Entry ) +{ + int i; + Vec_FltGrow( p, nSize ); + for ( i = 0; i < nSize; i++ ) + p->pArray[i] = Entry; + p->nSize = nSize; +} + +/**Function************************************************************* + + Synopsis [Fills the vector with given number of entries.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_FltFillExtra( Vec_Flt_t * p, int nSize, float Entry ) +{ + int i; + if ( p->nSize >= nSize ) + return; + Vec_FltGrow( p, nSize ); + for ( i = p->nSize; i < nSize; i++ ) + p->pArray[i] = Entry; + p->nSize = nSize; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_FltShrink( Vec_Flt_t * p, int nSizeNew ) +{ + assert( p->nSize >= nSizeNew ); + p->nSize = nSizeNew; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_FltClear( Vec_Flt_t * p ) +{ + p->nSize = 0; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_FltPush( Vec_Flt_t * p, float Entry ) +{ + if ( p->nSize == p->nCap ) + { + if ( p->nCap < 16 ) + Vec_FltGrow( p, 16 ); + else + Vec_FltGrow( p, 2 * p->nCap ); + } + p->pArray[p->nSize++] = Entry; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_FltPushOrder( Vec_Flt_t * p, float Entry ) +{ + int i; + if ( p->nSize == p->nCap ) + { + if ( p->nCap < 16 ) + Vec_FltGrow( p, 16 ); + else + Vec_FltGrow( p, 2 * p->nCap ); + } + p->nSize++; + for ( i = p->nSize-2; i >= 0; i-- ) + if ( p->pArray[i] > Entry ) + p->pArray[i+1] = p->pArray[i]; + else + break; + p->pArray[i+1] = Entry; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Vec_FltPushUnique( Vec_Flt_t * p, float Entry ) +{ + int i; + for ( i = 0; i < p->nSize; i++ ) + if ( p->pArray[i] == Entry ) + return 1; + Vec_FltPush( p, Entry ); + return 0; +} + +/**Function************************************************************* + + Synopsis [Returns the last entry and removes it from the list.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline float Vec_FltPop( Vec_Flt_t * p ) +{ + assert( p->nSize > 0 ); + return p->pArray[--p->nSize]; +} + +/**Function************************************************************* + + Synopsis [Find entry.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Vec_FltFind( Vec_Flt_t * p, float Entry ) +{ + int i; + for ( i = 0; i < p->nSize; i++ ) + if ( p->pArray[i] == Entry ) + return i; + return -1; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Vec_FltRemove( Vec_Flt_t * p, float Entry ) +{ + int i; + for ( i = 0; i < p->nSize; i++ ) + if ( p->pArray[i] == Entry ) + break; + if ( i == p->nSize ) + return 0; + assert( i < p->nSize ); + for ( i++; i < p->nSize; i++ ) + p->pArray[i-1] = p->pArray[i]; + p->nSize--; + return 1; +} + +/**Function************************************************************* + + Synopsis [Comparison procedure for two floats.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Vec_FltSortCompare1( float * pp1, float * pp2 ) +{ + // for some reason commenting out lines (as shown) led to crashing of the release version + if ( *pp1 < *pp2 ) + return -1; + if ( *pp1 > *pp2 ) // + return 1; + return 0; // +} + +/**Function************************************************************* + + Synopsis [Comparison procedure for two floats.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Vec_FltSortCompare2( float * pp1, float * pp2 ) +{ + // for some reason commenting out lines (as shown) led to crashing of the release version + if ( *pp1 > *pp2 ) + return -1; + if ( *pp1 < *pp2 ) // + return 1; + return 0; // +} + +/**Function************************************************************* + + Synopsis [Sorting the entries by their value.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_FltSort( Vec_Flt_t * p, int fReverse ) +{ + if ( fReverse ) + qsort( (void *)p->pArray, p->nSize, sizeof(float), + (int (*)(const void *, const void *)) Vec_FltSortCompare2 ); + else + qsort( (void *)p->pArray, p->nSize, sizeof(float), + (int (*)(const void *, const void *)) Vec_FltSortCompare1 ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + +#endif + diff --git a/src/misc/vec/vecInt.h b/src/misc/vec/vecInt.h new file mode 100644 index 00000000..082ebe70 --- /dev/null +++ b/src/misc/vec/vecInt.h @@ -0,0 +1,834 @@ +/**CFile**************************************************************** + + FileName [vecInt.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Resizable arrays.] + + Synopsis [Resizable arrays of integers.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: vecInt.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#ifndef __VEC_INT_H__ +#define __VEC_INT_H__ + +//////////////////////////////////////////////////////////////////////// +/// INCLUDES /// +//////////////////////////////////////////////////////////////////////// + +#include + +//////////////////////////////////////////////////////////////////////// +/// PARAMETERS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// BASIC TYPES /// +//////////////////////////////////////////////////////////////////////// + +typedef struct Vec_Int_t_ Vec_Int_t; +struct Vec_Int_t_ +{ + int nCap; + int nSize; + int * pArray; +}; + +//////////////////////////////////////////////////////////////////////// +/// MACRO DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +#define Vec_IntForEachEntry( vVec, Entry, i ) \ + for ( i = 0; (i < Vec_IntSize(vVec)) && (((Entry) = Vec_IntEntry(vVec, i)), 1); i++ ) +#define Vec_IntForEachEntryStart( vVec, Entry, i, Start ) \ + for ( i = Start; (i < Vec_IntSize(vVec)) && (((Entry) = Vec_IntEntry(vVec, i)), 1); i++ ) +#define Vec_IntForEachEntryStartStop( vVec, Entry, i, Start, Stop ) \ + for ( i = Start; (i < Stop) && (((Entry) = Vec_IntEntry(vVec, i)), 1); i++ ) +#define Vec_IntForEachEntryReverse( vVec, pEntry, i ) \ + for ( i = Vec_IntSize(vVec) - 1; (i >= 0) && (((pEntry) = Vec_IntEntry(vVec, i)), 1); i-- ) + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Allocates a vector with the given capacity.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Int_t * Vec_IntAlloc( int nCap ) +{ + Vec_Int_t * p; + p = ALLOC( Vec_Int_t, 1 ); + if ( nCap > 0 && nCap < 16 ) + nCap = 16; + p->nSize = 0; + p->nCap = nCap; + p->pArray = p->nCap? ALLOC( int, p->nCap ) : NULL; + return p; +} + +/**Function************************************************************* + + Synopsis [Allocates a vector with the given size and cleans it.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Int_t * Vec_IntStart( int nSize ) +{ + Vec_Int_t * p; + p = Vec_IntAlloc( nSize ); + p->nSize = nSize; + memset( p->pArray, 0, sizeof(int) * nSize ); + return p; +} + +/**Function************************************************************* + + Synopsis [Allocates a vector with the given size and cleans it.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Int_t * Vec_IntStartNatural( int nSize ) +{ + Vec_Int_t * p; + int i; + p = Vec_IntAlloc( nSize ); + p->nSize = nSize; + for ( i = 0; i < nSize; i++ ) + p->pArray[i] = i; + return p; +} + +/**Function************************************************************* + + Synopsis [Creates the vector from an integer array of the given size.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Int_t * Vec_IntAllocArray( int * pArray, int nSize ) +{ + Vec_Int_t * p; + p = ALLOC( Vec_Int_t, 1 ); + p->nSize = nSize; + p->nCap = nSize; + p->pArray = pArray; + return p; +} + +/**Function************************************************************* + + Synopsis [Creates the vector from an integer array of the given size.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Int_t * Vec_IntAllocArrayCopy( int * pArray, int nSize ) +{ + Vec_Int_t * p; + p = ALLOC( Vec_Int_t, 1 ); + p->nSize = nSize; + p->nCap = nSize; + p->pArray = ALLOC( int, nSize ); + memcpy( p->pArray, pArray, sizeof(int) * nSize ); + return p; +} + +/**Function************************************************************* + + Synopsis [Duplicates the integer array.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Int_t * Vec_IntDup( Vec_Int_t * pVec ) +{ + Vec_Int_t * p; + p = ALLOC( Vec_Int_t, 1 ); + p->nSize = pVec->nSize; + p->nCap = pVec->nSize; + p->pArray = p->nCap? ALLOC( int, p->nCap ) : NULL; + memcpy( p->pArray, pVec->pArray, sizeof(int) * pVec->nSize ); + return p; +} + +/**Function************************************************************* + + Synopsis [Transfers the array into another vector.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Int_t * Vec_IntDupArray( Vec_Int_t * pVec ) +{ + Vec_Int_t * p; + p = ALLOC( Vec_Int_t, 1 ); + p->nSize = pVec->nSize; + p->nCap = pVec->nCap; + p->pArray = pVec->pArray; + pVec->nSize = 0; + pVec->nCap = 0; + pVec->pArray = NULL; + return p; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_IntFree( Vec_Int_t * p ) +{ + FREE( p->pArray ); + FREE( p ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int * Vec_IntReleaseArray( Vec_Int_t * p ) +{ + int * pArray = p->pArray; + p->nCap = 0; + p->nSize = 0; + p->pArray = NULL; + return pArray; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int * Vec_IntArray( Vec_Int_t * p ) +{ + return p->pArray; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Vec_IntSize( Vec_Int_t * p ) +{ + return p->nSize; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Vec_IntEntry( Vec_Int_t * p, int i ) +{ + assert( i >= 0 && i < p->nSize ); + return p->pArray[i]; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_IntWriteEntry( Vec_Int_t * p, int i, int Entry ) +{ + assert( i >= 0 && i < p->nSize ); + p->pArray[i] = Entry; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_IntAddToEntry( Vec_Int_t * p, int i, int Addition ) +{ + assert( i >= 0 && i < p->nSize ); + p->pArray[i] += Addition; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Vec_IntEntryLast( Vec_Int_t * p ) +{ + assert( p->nSize > 0 ); + return p->pArray[p->nSize-1]; +} + +/**Function************************************************************* + + Synopsis [Resizes the vector to the given capacity.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_IntGrow( Vec_Int_t * p, int nCapMin ) +{ + if ( p->nCap >= nCapMin ) + return; + p->pArray = REALLOC( int, p->pArray, nCapMin ); + assert( p->pArray ); + p->nCap = nCapMin; +} + +/**Function************************************************************* + + Synopsis [Fills the vector with given number of entries.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_IntFill( Vec_Int_t * p, int nSize, int Entry ) +{ + int i; + Vec_IntGrow( p, nSize ); + for ( i = 0; i < nSize; i++ ) + p->pArray[i] = Entry; + p->nSize = nSize; +} + +/**Function************************************************************* + + Synopsis [Fills the vector with given number of entries.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_IntFillExtra( Vec_Int_t * p, int nSize, int Entry ) +{ + int i; + if ( p->nSize >= nSize ) + return; + Vec_IntGrow( p, nSize ); + for ( i = p->nSize; i < nSize; i++ ) + p->pArray[i] = Entry; + p->nSize = nSize; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_IntShrink( Vec_Int_t * p, int nSizeNew ) +{ + assert( p->nSize >= nSizeNew ); + p->nSize = nSizeNew; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_IntClear( Vec_Int_t * p ) +{ + p->nSize = 0; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_IntPush( Vec_Int_t * p, int Entry ) +{ + if ( p->nSize == p->nCap ) + { + if ( p->nCap < 16 ) + Vec_IntGrow( p, 16 ); + else + Vec_IntGrow( p, 2 * p->nCap ); + } + p->pArray[p->nSize++] = Entry; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_IntPushFirst( Vec_Int_t * p, int Entry ) +{ + int i; + if ( p->nSize == p->nCap ) + { + if ( p->nCap < 16 ) + Vec_IntGrow( p, 16 ); + else + Vec_IntGrow( p, 2 * p->nCap ); + } + p->nSize++; + for ( i = p->nSize - 1; i >= 1; i-- ) + p->pArray[i] = p->pArray[i-1]; + p->pArray[0] = Entry; +} + +/**Function************************************************************* + + Synopsis [Inserts the entry while preserving the increasing order.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_IntPushOrder( Vec_Int_t * p, int Entry ) +{ + int i; + if ( p->nSize == p->nCap ) + { + if ( p->nCap < 16 ) + Vec_IntGrow( p, 16 ); + else + Vec_IntGrow( p, 2 * p->nCap ); + } + p->nSize++; + for ( i = p->nSize-2; i >= 0; i-- ) + if ( p->pArray[i] > Entry ) + p->pArray[i+1] = p->pArray[i]; + else + break; + p->pArray[i+1] = Entry; +} + +/**Function************************************************************* + + Synopsis [Inserts the entry while preserving the increasing order.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Vec_IntPushUniqueOrder( Vec_Int_t * p, int Entry ) +{ + int i; + for ( i = 0; i < p->nSize; i++ ) + if ( p->pArray[i] == Entry ) + return 1; + Vec_IntPushOrder( p, Entry ); + return 0; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Vec_IntPushUnique( Vec_Int_t * p, int Entry ) +{ + int i; + for ( i = 0; i < p->nSize; i++ ) + if ( p->pArray[i] == Entry ) + return 1; + Vec_IntPush( p, Entry ); + return 0; +} + +/**Function************************************************************* + + Synopsis [Returns the pointer to the next nWords entries in the vector.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline unsigned * Vec_IntFetch( Vec_Int_t * p, int nWords ) +{ + if ( nWords == 0 ) + return NULL; + assert( nWords > 0 ); + p->nSize += nWords; + if ( p->nSize > p->nCap ) + { +// Vec_IntGrow( p, 2 * p->nSize ); + return NULL; + } + return ((unsigned *)p->pArray) + p->nSize - nWords; +} + +/**Function************************************************************* + + Synopsis [Returns the last entry and removes it from the list.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Vec_IntPop( Vec_Int_t * p ) +{ + assert( p->nSize > 0 ); + return p->pArray[--p->nSize]; +} + +/**Function************************************************************* + + Synopsis [Find entry.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Vec_IntFind( Vec_Int_t * p, int Entry ) +{ + int i; + for ( i = 0; i < p->nSize; i++ ) + if ( p->pArray[i] == Entry ) + return i; + return -1; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Vec_IntRemove( Vec_Int_t * p, int Entry ) +{ + int i; + for ( i = 0; i < p->nSize; i++ ) + if ( p->pArray[i] == Entry ) + break; + if ( i == p->nSize ) + return 0; + assert( i < p->nSize ); + for ( i++; i < p->nSize; i++ ) + p->pArray[i-1] = p->pArray[i]; + p->nSize--; + return 1; +} + +/**Function************************************************************* + + Synopsis [Comparison procedure for two integers.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Vec_IntSortCompare1( int * pp1, int * pp2 ) +{ + // for some reason commenting out lines (as shown) led to crashing of the release version + if ( *pp1 < *pp2 ) + return -1; + if ( *pp1 > *pp2 ) // + return 1; + return 0; // +} + +/**Function************************************************************* + + Synopsis [Comparison procedure for two integers.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Vec_IntSortCompare2( int * pp1, int * pp2 ) +{ + // for some reason commenting out lines (as shown) led to crashing of the release version + if ( *pp1 > *pp2 ) + return -1; + if ( *pp1 < *pp2 ) // + return 1; + return 0; // +} + +/**Function************************************************************* + + Synopsis [Sorting the entries by their integer value.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_IntSort( Vec_Int_t * p, int fReverse ) +{ + if ( fReverse ) + qsort( (void *)p->pArray, p->nSize, sizeof(int), + (int (*)(const void *, const void *)) Vec_IntSortCompare2 ); + else + qsort( (void *)p->pArray, p->nSize, sizeof(int), + (int (*)(const void *, const void *)) Vec_IntSortCompare1 ); +} + + +/**Function************************************************************* + + Synopsis [Comparison procedure for two integers.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Vec_IntSortCompareUnsigned( unsigned * pp1, unsigned * pp2 ) +{ + if ( *pp1 < *pp2 ) + return -1; + if ( *pp1 > *pp2 ) + return 1; + return 0; +} + +/**Function************************************************************* + + Synopsis [Sorting the entries by their integer value.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_IntSortUnsigned( Vec_Int_t * p ) +{ + qsort( (void *)p->pArray, p->nSize, sizeof(int), + (int (*)(const void *, const void *)) Vec_IntSortCompareUnsigned ); +} + +/**Function************************************************************* + + Synopsis [Returns the number of common entries.] + + Description [Assumes that the vectors are sorted in the increasing order.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Vec_IntTwoCountCommon( Vec_Int_t * vArr1, Vec_Int_t * vArr2 ) +{ + int * pBeg1 = vArr1->pArray; + int * pBeg2 = vArr2->pArray; + int * pEnd1 = vArr1->pArray + vArr1->nSize; + int * pEnd2 = vArr2->pArray + vArr2->nSize; + int Counter = 0; + while ( pBeg1 < pEnd1 && pBeg2 < pEnd2 ) + { + if ( *pBeg1 == *pBeg2 ) + pBeg1++, pBeg2++, Counter++; + else if ( *pBeg1 < *pBeg2 ) + pBeg1++; + else + pBeg2++; + } + return Counter; +} + +/**Function************************************************************* + + Synopsis [Returns the result of merging the two vectors.] + + Description [Assumes that the vectors are sorted in the increasing order.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Int_t * Vec_IntTwoMerge( Vec_Int_t * vArr1, Vec_Int_t * vArr2 ) +{ + Vec_Int_t * vArr = Vec_IntAlloc( vArr1->nSize + vArr2->nSize ); + int * pBeg = vArr->pArray; + int * pBeg1 = vArr1->pArray; + int * pBeg2 = vArr2->pArray; + int * pEnd1 = vArr1->pArray + vArr1->nSize; + int * pEnd2 = vArr2->pArray + vArr2->nSize; + while ( pBeg1 < pEnd1 && pBeg2 < pEnd2 ) + { + if ( *pBeg1 == *pBeg2 ) + *pBeg++ = *pBeg1++, pBeg2++; + else if ( *pBeg1 < *pBeg2 ) + *pBeg++ = *pBeg1++; + else + *pBeg++ = *pBeg2++; + } + while ( pBeg1 < pEnd1 ) + *pBeg++ = *pBeg1++; + while ( pBeg2 < pEnd2 ) + *pBeg++ = *pBeg2++; + vArr->nSize = pBeg - vArr->pArray; + assert( vArr->nSize <= vArr->nCap ); + assert( vArr->nSize >= vArr1->nSize ); + assert( vArr->nSize >= vArr2->nSize ); + return vArr; +} + +#endif + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + diff --git a/src/misc/vec/vecPtr.h b/src/misc/vec/vecPtr.h new file mode 100644 index 00000000..1862bc7c --- /dev/null +++ b/src/misc/vec/vecPtr.h @@ -0,0 +1,762 @@ +/**CFile**************************************************************** + + FileName [vecPtr.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Resizable arrays.] + + Synopsis [Resizable arrays of generic pointers.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: vecPtr.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#ifndef __VEC_PTR_H__ +#define __VEC_PTR_H__ + +//////////////////////////////////////////////////////////////////////// +/// INCLUDES /// +//////////////////////////////////////////////////////////////////////// + +#include + +//////////////////////////////////////////////////////////////////////// +/// PARAMETERS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// BASIC TYPES /// +//////////////////////////////////////////////////////////////////////// + +typedef struct Vec_Ptr_t_ Vec_Ptr_t; +struct Vec_Ptr_t_ +{ + int nCap; + int nSize; + void ** pArray; +}; + +//////////////////////////////////////////////////////////////////////// +/// MACRO DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +// iterators through entries +#define Vec_PtrForEachEntry( vVec, pEntry, i ) \ + for ( i = 0; (i < Vec_PtrSize(vVec)) && (((pEntry) = Vec_PtrEntry(vVec, i)), 1); i++ ) +#define Vec_PtrForEachEntryStart( vVec, pEntry, i, Start ) \ + for ( i = Start; (i < Vec_PtrSize(vVec)) && (((pEntry) = Vec_PtrEntry(vVec, i)), 1); i++ ) +#define Vec_PtrForEachEntryStop( vVec, pEntry, i, Stop ) \ + for ( i = 0; (i < Stop) && (((pEntry) = Vec_PtrEntry(vVec, i)), 1); i++ ) +#define Vec_PtrForEachEntryStartStop( vVec, pEntry, i, Start, Stop ) \ + for ( i = Start; (i < Stop) && (((pEntry) = Vec_PtrEntry(vVec, i)), 1); i++ ) +#define Vec_PtrForEachEntryReverse( vVec, pEntry, i ) \ + for ( i = Vec_PtrSize(vVec) - 1; (i >= 0) && (((pEntry) = Vec_PtrEntry(vVec, i)), 1); i-- ) + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Allocates a vector with the given capacity.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Ptr_t * Vec_PtrAlloc( int nCap ) +{ + Vec_Ptr_t * p; + p = ALLOC( Vec_Ptr_t, 1 ); + if ( nCap > 0 && nCap < 8 ) + nCap = 8; + p->nSize = 0; + p->nCap = nCap; + p->pArray = p->nCap? ALLOC( void *, p->nCap ) : NULL; + return p; +} + +/**Function************************************************************* + + Synopsis [Allocates a vector with the given size and cleans it.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Ptr_t * Vec_PtrStart( int nSize ) +{ + Vec_Ptr_t * p; + p = Vec_PtrAlloc( nSize ); + p->nSize = nSize; + memset( p->pArray, 0, sizeof(void *) * nSize ); + return p; +} + +/**Function************************************************************* + + Synopsis [Creates the vector from an integer array of the given size.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Ptr_t * Vec_PtrAllocArray( void ** pArray, int nSize ) +{ + Vec_Ptr_t * p; + p = ALLOC( Vec_Ptr_t, 1 ); + p->nSize = nSize; + p->nCap = nSize; + p->pArray = pArray; + return p; +} + +/**Function************************************************************* + + Synopsis [Creates the vector from an integer array of the given size.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Ptr_t * Vec_PtrAllocArrayCopy( void ** pArray, int nSize ) +{ + Vec_Ptr_t * p; + p = ALLOC( Vec_Ptr_t, 1 ); + p->nSize = nSize; + p->nCap = nSize; + p->pArray = ALLOC( void *, nSize ); + memcpy( p->pArray, pArray, sizeof(void *) * nSize ); + return p; +} + +/**Function************************************************************* + + Synopsis [Allocates the array of simulation info.] + + Description [Allocates the array containing given number of entries, + each of which contains given number of unsigned words of simulation data. + The resulting array can be freed using regular procedure Vec_PtrFree(). + It is the responsibility of the user to ensure this array is never grown.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Ptr_t * Vec_PtrAllocSimInfo( int nEntries, int nWords ) +{ + void ** pMemory; + unsigned * pInfo; + int i; + pMemory = (void **)ALLOC( char, (sizeof(void *) + sizeof(unsigned) * nWords) * nEntries ); + pInfo = (unsigned *)(pMemory + nEntries); + for ( i = 0; i < nEntries; i++ ) + pMemory[i] = pInfo + i * nWords; + return Vec_PtrAllocArray( pMemory, nEntries ); +} + +/**Function************************************************************* + + Synopsis [Allocates the array of truth tables for the given number of vars.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Ptr_t * Vec_PtrAllocTruthTables( int nVars ) +{ + Vec_Ptr_t * p; + unsigned Masks[5] = { 0xAAAAAAAA, 0xCCCCCCCC, 0xF0F0F0F0, 0xFF00FF00, 0xFFFF0000 }; + unsigned * pTruth; + int i, k, nWords; + nWords = (nVars <= 5 ? 1 : (1 << (nVars - 5))); + p = Vec_PtrAllocSimInfo( nVars, nWords ); + for ( i = 0; i < nVars; i++ ) + { + pTruth = (unsigned *)p->pArray[i]; + if ( i < 5 ) + { + for ( k = 0; k < nWords; k++ ) + pTruth[k] = Masks[i]; + } + else + { + for ( k = 0; k < nWords; k++ ) + if ( k & (1 << (i-5)) ) + pTruth[k] = ~(unsigned)0; + else + pTruth[k] = 0; + } + } + return p; +} + +/**Function************************************************************* + + Synopsis [Duplicates the integer array.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Ptr_t * Vec_PtrDup( Vec_Ptr_t * pVec ) +{ + Vec_Ptr_t * p; + p = ALLOC( Vec_Ptr_t, 1 ); + p->nSize = pVec->nSize; + p->nCap = pVec->nCap; + p->pArray = p->nCap? ALLOC( void *, p->nCap ) : NULL; + memcpy( p->pArray, pVec->pArray, sizeof(void *) * pVec->nSize ); + return p; +} + +/**Function************************************************************* + + Synopsis [Transfers the array into another vector.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Ptr_t * Vec_PtrDupArray( Vec_Ptr_t * pVec ) +{ + Vec_Ptr_t * p; + p = ALLOC( Vec_Ptr_t, 1 ); + p->nSize = pVec->nSize; + p->nCap = pVec->nCap; + p->pArray = pVec->pArray; + pVec->nSize = 0; + pVec->nCap = 0; + pVec->pArray = NULL; + return p; +} + +/**Function************************************************************* + + Synopsis [Frees the vector.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_PtrFree( Vec_Ptr_t * p ) +{ + FREE( p->pArray ); + FREE( p ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void ** Vec_PtrReleaseArray( Vec_Ptr_t * p ) +{ + void ** pArray = p->pArray; + p->nCap = 0; + p->nSize = 0; + p->pArray = NULL; + return pArray; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void ** Vec_PtrArray( Vec_Ptr_t * p ) +{ + return p->pArray; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Vec_PtrSize( Vec_Ptr_t * p ) +{ + return p->nSize; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void * Vec_PtrEntry( Vec_Ptr_t * p, int i ) +{ + assert( i >= 0 && i < p->nSize ); + return p->pArray[i]; +} + +/**Function************************************************************* + + Synopsis [Resizes the array of simulation info.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_PtrDoubleSimInfo( Vec_Ptr_t * vInfo ) +{ + Vec_Ptr_t * vInfoNew; + int nWords; + assert( Vec_PtrSize(vInfo) > 2 ); + // get the new array + nWords = (unsigned *)Vec_PtrEntry(vInfo,1) - (unsigned *)Vec_PtrEntry(vInfo,0); + vInfoNew = Vec_PtrAllocSimInfo( 2*Vec_PtrSize(vInfo), nWords ); + // copy the simulation info + memcpy( Vec_PtrEntry(vInfoNew,0), Vec_PtrEntry(vInfo,0), Vec_PtrSize(vInfo) * nWords * 4 ); + // replace the array + free( vInfo->pArray ); + vInfo->pArray = vInfoNew->pArray; + vInfo->nSize *= 2; + vInfo->nCap *= 2; + // free the old array + vInfoNew->pArray = NULL; + free( vInfoNew ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void ** Vec_PtrEntryP( Vec_Ptr_t * p, int i ) +{ + assert( i >= 0 && i < p->nSize ); + return p->pArray + i; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_PtrWriteEntry( Vec_Ptr_t * p, int i, void * Entry ) +{ + assert( i >= 0 && i < p->nSize ); + p->pArray[i] = Entry; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void * Vec_PtrEntryLast( Vec_Ptr_t * p ) +{ + assert( p->nSize > 0 ); + return p->pArray[p->nSize-1]; +} + +/**Function************************************************************* + + Synopsis [Resizes the vector to the given capacity.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_PtrGrow( Vec_Ptr_t * p, int nCapMin ) +{ + if ( p->nCap >= nCapMin ) + return; + p->pArray = REALLOC( void *, p->pArray, nCapMin ); + p->nCap = nCapMin; +} + +/**Function************************************************************* + + Synopsis [Fills the vector with given number of entries.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_PtrFill( Vec_Ptr_t * p, int nSize, void * Entry ) +{ + int i; + Vec_PtrGrow( p, nSize ); + for ( i = 0; i < nSize; i++ ) + p->pArray[i] = Entry; + p->nSize = nSize; +} + +/**Function************************************************************* + + Synopsis [Fills the vector with given number of entries.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_PtrFillExtra( Vec_Ptr_t * p, int nSize, void * Entry ) +{ + int i; + if ( p->nSize >= nSize ) + return; + assert( p->nSize < nSize ); + if ( 2 * p->nSize > nSize ) + Vec_PtrGrow( p, 2 * nSize ); + else + Vec_PtrGrow( p, nSize ); + for ( i = p->nSize; i < nSize; i++ ) + p->pArray[i] = Entry; + p->nSize = nSize; +} + +/**Function************************************************************* + + Synopsis [Returns the entry even if the place not exist.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void * Vec_PtrGetEntry( Vec_Ptr_t * p, int i ) +{ + Vec_PtrFillExtra( p, i + 1, NULL ); + return Vec_PtrEntry( p, i ); +} + +/**Function************************************************************* + + Synopsis [Inserts the entry even if the place does not exist.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_PtrSetEntry( Vec_Ptr_t * p, int i, void * Entry ) +{ + Vec_PtrFillExtra( p, i + 1, NULL ); + Vec_PtrWriteEntry( p, i, Entry ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_PtrShrink( Vec_Ptr_t * p, int nSizeNew ) +{ + assert( p->nSize >= nSizeNew ); + p->nSize = nSizeNew; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_PtrClear( Vec_Ptr_t * p ) +{ + p->nSize = 0; +} + +/**Function************************************************************* + + Synopsis [Copies the interger array.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_PtrCopy( Vec_Ptr_t * pDest, Vec_Ptr_t * pSour ) +{ + pDest->nSize = 0; + Vec_PtrGrow( pDest, pSour->nSize ); + memcpy( pDest->pArray, pSour->pArray, sizeof(void *) * pSour->nSize ); + pDest->nSize = pSour->nSize; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_PtrPush( Vec_Ptr_t * p, void * Entry ) +{ + if ( p->nSize == p->nCap ) + { + if ( p->nCap < 16 ) + Vec_PtrGrow( p, 16 ); + else + Vec_PtrGrow( p, 2 * p->nCap ); + } + p->pArray[p->nSize++] = Entry; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Vec_PtrPushUnique( Vec_Ptr_t * p, void * Entry ) +{ + int i; + for ( i = 0; i < p->nSize; i++ ) + if ( p->pArray[i] == Entry ) + return 1; + Vec_PtrPush( p, Entry ); + return 0; +} + +/**Function************************************************************* + + Synopsis [Returns the last entry and removes it from the list.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void * Vec_PtrPop( Vec_Ptr_t * p ) +{ + assert( p->nSize > 0 ); + return p->pArray[--p->nSize]; +} + +/**Function************************************************************* + + Synopsis [Find entry.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Vec_PtrFind( Vec_Ptr_t * p, void * Entry ) +{ + int i; + for ( i = 0; i < p->nSize; i++ ) + if ( p->pArray[i] == Entry ) + return i; + return -1; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_PtrRemove( Vec_Ptr_t * p, void * Entry ) +{ + int i; + // delete assuming that it is closer to the end + for ( i = p->nSize - 1; i >= 0; i-- ) + if ( p->pArray[i] == Entry ) + break; + assert( i >= 0 ); +/* + // delete assuming that it is closer to the beginning + for ( i = 0; i < p->nSize; i++ ) + if ( p->pArray[i] == Entry ) + break; + assert( i < p->nSize ); +*/ + for ( i++; i < p->nSize; i++ ) + p->pArray[i-1] = p->pArray[i]; + p->nSize--; +} + +/**Function************************************************************* + + Synopsis [Moves the first nItems to the end.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_PtrReorder( Vec_Ptr_t * p, int nItems ) +{ + assert( nItems < p->nSize ); + Vec_PtrGrow( p, nItems + p->nSize ); + memmove( (char **)p->pArray + p->nSize, p->pArray, nItems * sizeof(void*) ); + memmove( p->pArray, (char **)p->pArray + nItems, p->nSize * sizeof(void*) ); +} + +/**Function************************************************************* + + Synopsis [Sorting the entries by their integer value.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_PtrSort( Vec_Ptr_t * p, int (*Vec_PtrSortCompare)() ) +{ + if ( p->nSize < 2 ) + return; + qsort( (void *)p->pArray, p->nSize, sizeof(void *), + (int (*)(const void *, const void *)) Vec_PtrSortCompare ); +} + +/**Function************************************************************* + + Synopsis [Sorting the entries by their integer value.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_PtrUniqify( Vec_Ptr_t * p, int (*Vec_PtrSortCompare)() ) +{ + int i, k; + if ( p->nSize < 2 ) + return; + qsort( (void *)p->pArray, p->nSize, sizeof(void *), + (int (*)(const void *, const void *)) Vec_PtrSortCompare ); + for ( i = k = 1; i < p->nSize; i++ ) + if ( p->pArray[i] != p->pArray[i-1] ) + p->pArray[k++] = p->pArray[i]; + p->nSize = k; +} + +#endif + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + diff --git a/src/misc/vec/vecStr.h b/src/misc/vec/vecStr.h new file mode 100644 index 00000000..47367bc6 --- /dev/null +++ b/src/misc/vec/vecStr.h @@ -0,0 +1,583 @@ +/**CFile**************************************************************** + + FileName [vecStr.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Resizable arrays.] + + Synopsis [Resizable arrays of characters.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: vecStr.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#ifndef __VEC_STR_H__ +#define __VEC_STR_H__ + +//////////////////////////////////////////////////////////////////////// +/// INCLUDES /// +//////////////////////////////////////////////////////////////////////// + +#include + +//////////////////////////////////////////////////////////////////////// +/// PARAMETERS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// BASIC TYPES /// +//////////////////////////////////////////////////////////////////////// + +typedef struct Vec_Str_t_ Vec_Str_t; +struct Vec_Str_t_ +{ + int nCap; + int nSize; + char * pArray; +}; + +//////////////////////////////////////////////////////////////////////// +/// MACRO DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +#define Vec_StrForEachEntry( vVec, Entry, i ) \ + for ( i = 0; (i < Vec_StrSize(vVec)) && (((Entry) = Vec_StrEntry(vVec, i)), 1); i++ ) + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Allocates a vector with the given capacity.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Str_t * Vec_StrAlloc( int nCap ) +{ + Vec_Str_t * p; + p = ALLOC( Vec_Str_t, 1 ); + if ( nCap > 0 && nCap < 16 ) + nCap = 16; + p->nSize = 0; + p->nCap = nCap; + p->pArray = p->nCap? ALLOC( char, p->nCap ) : NULL; + return p; +} + +/**Function************************************************************* + + Synopsis [Allocates a vector with the given size and cleans it.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Str_t * Vec_StrStart( int nSize ) +{ + Vec_Str_t * p; + p = Vec_StrAlloc( nSize ); + p->nSize = nSize; + memset( p->pArray, 0, sizeof(char) * nSize ); + return p; +} + +/**Function************************************************************* + + Synopsis [Creates the vector from an integer array of the given size.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Str_t * Vec_StrAllocArray( char * pArray, int nSize ) +{ + Vec_Str_t * p; + p = ALLOC( Vec_Str_t, 1 ); + p->nSize = nSize; + p->nCap = nSize; + p->pArray = pArray; + return p; +} + +/**Function************************************************************* + + Synopsis [Creates the vector from an integer array of the given size.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Str_t * Vec_StrAllocArrayCopy( char * pArray, int nSize ) +{ + Vec_Str_t * p; + p = ALLOC( Vec_Str_t, 1 ); + p->nSize = nSize; + p->nCap = nSize; + p->pArray = ALLOC( char, nSize ); + memcpy( p->pArray, pArray, sizeof(char) * nSize ); + return p; +} + +/**Function************************************************************* + + Synopsis [Duplicates the integer array.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Str_t * Vec_StrDup( Vec_Str_t * pVec ) +{ + Vec_Str_t * p; + p = ALLOC( Vec_Str_t, 1 ); + p->nSize = pVec->nSize; + p->nCap = pVec->nCap; + p->pArray = p->nCap? ALLOC( char, p->nCap ) : NULL; + memcpy( p->pArray, pVec->pArray, sizeof(char) * pVec->nSize ); + return p; +} + +/**Function************************************************************* + + Synopsis [Transfers the array into another vector.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Str_t * Vec_StrDupArray( Vec_Str_t * pVec ) +{ + Vec_Str_t * p; + p = ALLOC( Vec_Str_t, 1 ); + p->nSize = pVec->nSize; + p->nCap = pVec->nCap; + p->pArray = pVec->pArray; + pVec->nSize = 0; + pVec->nCap = 0; + pVec->pArray = NULL; + return p; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_StrFree( Vec_Str_t * p ) +{ + FREE( p->pArray ); + FREE( p ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline char * Vec_StrReleaseArray( Vec_Str_t * p ) +{ + char * pArray = p->pArray; + p->nCap = 0; + p->nSize = 0; + p->pArray = NULL; + return pArray; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline char * Vec_StrArray( Vec_Str_t * p ) +{ + return p->pArray; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Vec_StrSize( Vec_Str_t * p ) +{ + return p->nSize; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline char Vec_StrEntry( Vec_Str_t * p, int i ) +{ + assert( i >= 0 && i < p->nSize ); + return p->pArray[i]; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_StrWriteEntry( Vec_Str_t * p, int i, char Entry ) +{ + assert( i >= 0 && i < p->nSize ); + p->pArray[i] = Entry; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline char Vec_StrEntryLast( Vec_Str_t * p ) +{ + assert( p->nSize > 0 ); + return p->pArray[p->nSize-1]; +} + +/**Function************************************************************* + + Synopsis [Resizes the vector to the given capacity.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_StrGrow( Vec_Str_t * p, int nCapMin ) +{ + if ( p->nCap >= nCapMin ) + return; + p->pArray = REALLOC( char, p->pArray, 2 * nCapMin ); + p->nCap = 2 * nCapMin; +} + +/**Function************************************************************* + + Synopsis [Fills the vector with given number of entries.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_StrFill( Vec_Str_t * p, int nSize, char Entry ) +{ + int i; + Vec_StrGrow( p, nSize ); + p->nSize = nSize; + for ( i = 0; i < p->nSize; i++ ) + p->pArray[i] = Entry; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_StrShrink( Vec_Str_t * p, int nSizeNew ) +{ + assert( p->nSize >= nSizeNew ); + p->nSize = nSizeNew; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_StrClear( Vec_Str_t * p ) +{ + p->nSize = 0; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_StrPush( Vec_Str_t * p, char Entry ) +{ + if ( p->nSize == p->nCap ) + { + if ( p->nCap < 16 ) + Vec_StrGrow( p, 16 ); + else + Vec_StrGrow( p, 2 * p->nCap ); + } + p->pArray[p->nSize++] = Entry; +} + +/**Function******************************************************************** + + Synopsis [Finds the smallest integer larger of equal than the logarithm.] + + Description [Returns [Log10(Num)].] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +static inline int Vec_StrBase10Log( unsigned Num ) +{ + int Res; + assert( Num >= 0 ); + if ( Num == 0 ) return 0; + if ( Num == 1 ) return 1; + for ( Res = 0, Num--; Num; Num /= 10, Res++ ); + return Res; +} /* end of Extra_Base2Log */ + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_StrPrintNum( Vec_Str_t * p, int Num ) +{ + int i, nDigits; + if ( Num < 0 ) + { + Vec_StrPush( p, '-' ); + Num = -Num; + } + if ( Num < 10 ) + { + Vec_StrPush( p, (char)('0' + Num) ); + return; + } + nDigits = Vec_StrBase10Log( Num ); + Vec_StrGrow( p, p->nSize + nDigits ); + for ( i = nDigits - 1; i >= 0; i-- ) + { + Vec_StrWriteEntry( p, p->nSize + i, (char)('0' + Num % 10) ); + Num /= 10; + } + assert( Num == 0 ); + p->nSize += nDigits; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_StrPrintStr( Vec_Str_t * p, char * pStr ) +{ + int i, Length = strlen(pStr); + for ( i = 0; i < Length; i++ ) + Vec_StrPush( p, pStr[i] ); +} + +/**Function************************************************************* + + Synopsis [Appends the string to the char vector.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_StrAppend( Vec_Str_t * p, char * pString ) +{ + int i, nLength = strlen(pString); + Vec_StrGrow( p, p->nSize + nLength ); + for ( i = 0; i < nLength; i++ ) + p->pArray[p->nSize + i] = pString[i]; + p->nSize += nLength; +} + +/**Function************************************************************* + + Synopsis [Returns the last entry and removes it from the list.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline char Vec_StrPop( Vec_Str_t * p ) +{ + assert( p->nSize > 0 ); + return p->pArray[--p->nSize]; +} + +/**Function************************************************************* + + Synopsis [Comparison procedure for two clauses.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Vec_StrSortCompare1( char * pp1, char * pp2 ) +{ + // for some reason commenting out lines (as shown) led to crashing of the release version + if ( *pp1 < *pp2 ) + return -1; + if ( *pp1 > *pp2 ) // + return 1; + return 0; // +} + +/**Function************************************************************* + + Synopsis [Comparison procedure for two clauses.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Vec_StrSortCompare2( char * pp1, char * pp2 ) +{ + // for some reason commenting out lines (as shown) led to crashing of the release version + if ( *pp1 > *pp2 ) + return -1; + if ( *pp1 < *pp2 ) // + return 1; + return 0; // +} + +/**Function************************************************************* + + Synopsis [Sorting the entries by their integer value.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_StrSort( Vec_Str_t * p, int fReverse ) +{ + if ( fReverse ) + qsort( (void *)p->pArray, p->nSize, sizeof(char), + (int (*)(const void *, const void *)) Vec_StrSortCompare2 ); + else + qsort( (void *)p->pArray, p->nSize, sizeof(char), + (int (*)(const void *, const void *)) Vec_StrSortCompare1 ); +} + +#endif + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + diff --git a/src/misc/vec/vecVec.h b/src/misc/vec/vecVec.h new file mode 100644 index 00000000..55ffdf4f --- /dev/null +++ b/src/misc/vec/vecVec.h @@ -0,0 +1,356 @@ +/**CFile**************************************************************** + + FileName [vecVec.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Resizable arrays.] + + Synopsis [Resizable vector of resizable vectors.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: vecVec.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#ifndef __VEC_VEC_H__ +#define __VEC_VEC_H__ + +//////////////////////////////////////////////////////////////////////// +/// INCLUDES /// +//////////////////////////////////////////////////////////////////////// + +#include + +//////////////////////////////////////////////////////////////////////// +/// PARAMETERS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// BASIC TYPES /// +//////////////////////////////////////////////////////////////////////// + +typedef struct Vec_Vec_t_ Vec_Vec_t; +struct Vec_Vec_t_ +{ + int nCap; + int nSize; + void ** pArray; +}; + +//////////////////////////////////////////////////////////////////////// +/// MACRO DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +// iterators through levels +#define Vec_VecForEachLevel( vGlob, vVec, i ) \ + for ( i = 0; (i < Vec_VecSize(vGlob)) && (((vVec) = (Vec_Ptr_t*)Vec_VecEntry(vGlob, i)), 1); i++ ) +#define Vec_VecForEachLevelStart( vGlob, vVec, i, LevelStart ) \ + for ( i = LevelStart; (i < Vec_VecSize(vGlob)) && (((vVec) = (Vec_Ptr_t*)Vec_VecEntry(vGlob, i)), 1); i++ ) +#define Vec_VecForEachLevelStartStop( vGlob, vVec, i, LevelStart, LevelStop ) \ + for ( i = LevelStart; (i <= LevelStop) && (((vVec) = (Vec_Ptr_t*)Vec_VecEntry(vGlob, i)), 1); i++ ) +#define Vec_VecForEachLevelReverse( vGlob, vVec, i ) \ + for ( i = Vec_VecSize(vGlob) - 1; (i >= 0) && (((vVec) = (Vec_Ptr_t*)Vec_VecEntry(vGlob, i)), 1); i-- ) +#define Vec_VecForEachLevelReverseStartStop( vGlob, vVec, i, LevelStart, LevelStop ) \ + for ( i = LevelStart; (i >= LevelStop) && (((vVec) = (Vec_Ptr_t*)Vec_VecEntry(vGlob, i)), 1); i-- ) + +// iteratores through entries +#define Vec_VecForEachEntry( vGlob, pEntry, i, k ) \ + for ( i = 0; i < Vec_VecSize(vGlob); i++ ) \ + Vec_PtrForEachEntry( Vec_VecEntry(vGlob, i), pEntry, k ) +#define Vec_VecForEachEntryLevel( vGlob, pEntry, i, Level ) \ + Vec_PtrForEachEntry( Vec_VecEntry(vGlob, Level), pEntry, i ) +#define Vec_VecForEachEntryStart( vGlob, pEntry, i, k, LevelStart ) \ + for ( i = LevelStart; i < Vec_VecSize(vGlob); i++ ) \ + Vec_PtrForEachEntry( Vec_VecEntry(vGlob, i), pEntry, k ) +#define Vec_VecForEachEntryStartStop( vGlob, pEntry, i, k, LevelStart, LevelStop ) \ + for ( i = LevelStart; i <= LevelStop; i++ ) \ + Vec_PtrForEachEntry( Vec_VecEntry(vGlob, i), pEntry, k ) +#define Vec_VecForEachEntryReverse( vGlob, pEntry, i, k ) \ + for ( i = 0; i < Vec_VecSize(vGlob); i++ ) \ + Vec_PtrForEachEntryReverse( Vec_VecEntry(vGlob, i), pEntry, k ) +#define Vec_VecForEachEntryReverseReverse( vGlob, pEntry, i, k ) \ + for ( i = Vec_VecSize(vGlob) - 1; i >= 0; i-- ) \ + Vec_PtrForEachEntryReverse( Vec_VecEntry(vGlob, i), pEntry, k ) +#define Vec_VecForEachEntryReverseStart( vGlob, pEntry, i, k, LevelStart ) \ + for ( i = LevelStart; i >= 0; i-- ) \ + Vec_PtrForEachEntry( Vec_VecEntry(vGlob, i), pEntry, k ) + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Allocates a vector with the given capacity.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Vec_t * Vec_VecAlloc( int nCap ) +{ + Vec_Vec_t * p; + p = ALLOC( Vec_Vec_t, 1 ); + if ( nCap > 0 && nCap < 8 ) + nCap = 8; + p->nSize = 0; + p->nCap = nCap; + p->pArray = p->nCap? ALLOC( void *, p->nCap ) : NULL; + return p; +} + +/**Function************************************************************* + + Synopsis [Allocates a vector with the given capacity.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Vec_Vec_t * Vec_VecStart( int nSize ) +{ + Vec_Vec_t * p; + int i; + p = Vec_VecAlloc( nSize ); + for ( i = 0; i < nSize; i++ ) + p->pArray[i] = Vec_PtrAlloc( 0 ); + p->nSize = nSize; + return p; +} + +/**Function************************************************************* + + Synopsis [Allocates a vector with the given capacity.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_VecExpand( Vec_Vec_t * p, int Level ) +{ + int i; + if ( p->nSize >= Level + 1 ) + return; + Vec_PtrGrow( (Vec_Ptr_t *)p, Level + 1 ); + for ( i = p->nSize; i <= Level; i++ ) + p->pArray[i] = Vec_PtrAlloc( 0 ); + p->nSize = Level + 1; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Vec_VecSize( Vec_Vec_t * p ) +{ + return p->nSize; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void * Vec_VecEntry( Vec_Vec_t * p, int i ) +{ + assert( i >= 0 && i < p->nSize ); + return p->pArray[i]; +} + +/**Function************************************************************* + + Synopsis [Frees the vector.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_VecFree( Vec_Vec_t * p ) +{ + Vec_Ptr_t * vVec; + int i; + Vec_VecForEachLevel( p, vVec, i ) + Vec_PtrFree( vVec ); + Vec_PtrFree( (Vec_Ptr_t *)p ); +} + +/**Function************************************************************* + + Synopsis [Frees the vector of vectors.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Vec_VecSizeSize( Vec_Vec_t * p ) +{ + Vec_Ptr_t * vVec; + int i, Counter = 0; + Vec_VecForEachLevel( p, vVec, i ) + Counter += vVec->nSize; + return Counter; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_VecClear( Vec_Vec_t * p ) +{ + Vec_Ptr_t * vVec; + int i; + Vec_VecForEachLevel( p, vVec, i ) + Vec_PtrClear( vVec ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_VecPush( Vec_Vec_t * p, int Level, void * Entry ) +{ + if ( p->nSize < Level + 1 ) + { + int i; + Vec_PtrGrow( (Vec_Ptr_t *)p, Level + 1 ); + for ( i = p->nSize; i < Level + 1; i++ ) + p->pArray[i] = Vec_PtrAlloc( 0 ); + p->nSize = Level + 1; + } + Vec_PtrPush( (Vec_Ptr_t*)p->pArray[Level], Entry ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_VecPushUnique( Vec_Vec_t * p, int Level, void * Entry ) +{ + if ( p->nSize < Level + 1 ) + Vec_VecPush( p, Level, Entry ); + else + Vec_PtrPushUnique( (Vec_Ptr_t*)p->pArray[Level], Entry ); +} + +/**Function************************************************************* + + Synopsis [Comparison procedure for two arrays.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Vec_VecSortCompare1( Vec_Ptr_t ** pp1, Vec_Ptr_t ** pp2 ) +{ + if ( Vec_PtrSize(*pp1) < Vec_PtrSize(*pp2) ) + return -1; + if ( Vec_PtrSize(*pp1) > Vec_PtrSize(*pp2) ) + return 1; + return 0; +} + +/**Function************************************************************* + + Synopsis [Comparison procedure for two integers.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Vec_VecSortCompare2( Vec_Ptr_t ** pp1, Vec_Ptr_t ** pp2 ) +{ + if ( Vec_PtrSize(*pp1) > Vec_PtrSize(*pp2) ) + return -1; + if ( Vec_PtrSize(*pp1) < Vec_PtrSize(*pp2) ) + return 1; + return 0; +} + +/**Function************************************************************* + + Synopsis [Sorting the entries by their integer value.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Vec_VecSort( Vec_Vec_t * p, int fReverse ) +{ + if ( fReverse ) + qsort( (void *)p->pArray, p->nSize, sizeof(void *), + (int (*)(const void *, const void *)) Vec_VecSortCompare2 ); + else + qsort( (void *)p->pArray, p->nSize, sizeof(void *), + (int (*)(const void *, const void *)) Vec_VecSortCompare1 ); +} + +#endif + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + -- cgit v1.2.3