#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();
pcover complement(T)
pcube *T;
{
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) {
cl = new_cube();
cr = new_cube();
best = binate_split_select(T, cl, cr, COMPL);
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;
pcover *Tbar;
{
register pcube *T1, p, ceil, cof=T[0];
pcover A, ceil_compl;
if (T[2] == NULL) {
*Tbar = sf_addset(new_cover(1), cube.fullset);
free_cubelist(T);
return TRUE;
}
if (T[3] == NULL) {
*Tbar = compl_cube(set_or(cof, cof, T[2]));
free_cubelist(T);
return TRUE;
}
for(T1 = T+2; (p = *T1++) != NULL; ) {
if (full_row(p, cof)) {
*Tbar = new_cover(0);
free_cubelist(T);
return TRUE;
}
}
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);
massive_count(T);
if (cdata.vars_active == 1) {
*Tbar = new_cover(0);
free_cubelist(T);
return TRUE;
} 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;
} else {
return MAYBE;
}
}
static pcover compl_merge(T1, L, R, cl, cr, var, lifting)
pcube *T1;
pcover L, R;
register pcube cl, cr;
int var;
int lifting;
{
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);
}
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);
}
(void) set_copy(cube.temp[0], cube.var_mask[var]);
qsort((char *) (L1 = sf_list(L)), (size_t)L->count, sizeof(pset), (int (*)()) d1_order);
qsort((char *) (R1 = sf_list(R)), (size_t)R->count, sizeof(pset), (int (*)()) d1_order);
compl_d1merge(L1, R1);
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);
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;
}
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(; (a = *A1++) != NULL; ) {
if (TESTP(a, ACTIVE)) {
(void) set_merge(lift, bcube, a, mask);
for(B2 = B1; (b = *B2++) != NULL; ) {
INLINEsetp_implies(lift, b, continue);
INLINEset_or(a, a, liftor);
break;
}
}
}
}
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(; (a = *A1++) != NULL; ) {
if (TESTP(a, ACTIVE)) {
INLINEset_and(lift, bcube, mask);
INLINEset_or(lift, a, lift);
foreach_set(T, last, p) {
if (cdist0(p, lift)) {
goto nolift;
}
}
INLINEset_copy(a, lift);
SET(a, ACTIVE);
nolift : ;
}
}
}
static void compl_lift_onset_complex(A1, T, var)
pcube *A1;
pcover T;
int var;
{
register int dist;
register pcube last, p, a, xlower;
xlower = new_cube();
for(; (a = *A1++) != NULL; ) {
if (TESTP(a, ACTIVE)) {
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);
}
}
}
static void compl_d1merge(L1, R1)
register pcube *L1, *R1;
{
register pcube pl, pr;
for(pl = *L1, pr = *R1; (pl != NULL) && (pr != NULL); )
switch (d1_order(L1, R1)) {
case 1:
pr = *(++R1); break;
case -1:
pl = *(++L1); break;
case 0:
RESET(pr, ACTIVE);
INLINEset_or(pl, pl, pr);
pr = *(++R1);
default:
;
}
}
static pcover compl_cube(p)
register pcube p;
{
register pcube diff=cube.temp[7], pdest, mask, full=cube.fullset;
int var;
pcover R;
R = new_cover(cube.num_vars);
INLINEset_diff(diff, full, p);
for(var = 0; var < cube.num_vars; var++) {
mask = cube.var_mask[var];
if (! setp_disjoint(diff, mask)) {
pdest = GETSET(R, R->count++);
INLINEset_merge(pdest, diff, full, mask);
}
}
return R;
}
void simp_comp(T, Tnew, Tbar)
pcube *T;
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) {
cl = new_cube();
cr = new_cube();
best = binate_split_select(T, cl, cr, COMPL);
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);
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;
pcover *Tnew;
pcover *Tbar;
{
register pcube *T1, p, ceil, cof=T[0];
pcube last;
pcover A;
if (T[2] == NULL) {
*Tnew = new_cover(1);
*Tbar = sf_addset(new_cover(1), cube.fullset);
free_cubelist(T);
return TRUE;
}
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;
}
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;
}
}
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);
A = *Tnew;
foreach_set(A, last, p) {
INLINEset_and(p, p, ceil);
}
*Tbar = sf_append(*Tbar, compl_cube(ceil));
set_free(ceil);
return TRUE;
}
set_free(ceil);
massive_count(T);
if (cdata.vars_active == 1) {
*Tnew = sf_addset(new_cover(1), cube.fullset);
*Tbar = new_cover(1);
free_cubelist(T);
return TRUE;
} else if (cdata.vars_unate == cdata.vars_active) {
A = cubeunlist(T);
*Tnew = sf_contain(A);
A = map_cover_to_unate(T);
A = unate_compl(A);
*Tbar = map_unate_to_cover(A);
sf_free(A);
free_cubelist(T);
return TRUE;
} else {
return MAYBE;
}
}
pcover simplify(T)
pcube *T;
{
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) {
cl = new_cube();
cr = new_cube();
best = binate_split_select(T, cl, cr, COMPL);
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);
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;
pcover *Tnew;
{
register pcube *T1, p, ceil, cof=T[0];
pcube last;
pcover A;
if (T[2] == NULL) {
*Tnew = new_cover(0);
free_cubelist(T);
return TRUE;
}
if (T[3] == NULL) {
*Tnew = sf_addset(new_cover(1), set_or(cof, cof, T[2]));
free_cubelist(T);
return TRUE;
}
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;
}
}
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);
massive_count(T);
if (cdata.vars_active == 1) {
*Tnew = sf_addset(new_cover(1), cube.fullset);
free_cubelist(T);
return TRUE;
} else if (cdata.vars_unate == cdata.vars_active) {
A = cubeunlist(T);
*Tnew = sf_contain(A);
free_cubelist(T);
return TRUE;
} else {
return MAYBE;
}
}
ABC_NAMESPACE_IMPL_END