mirror of https://github.com/YosysHQ/abc.git
686 lines
18 KiB
C
686 lines
18 KiB
C
/*
|
||
* 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"
|
||
|
||
ABC_NAMESPACE_IMPL_START
|
||
|
||
|
||
#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;
|
||
}
|
||
}
|
||
ABC_NAMESPACE_IMPL_END
|
||
|