#include "espresso.h"
ABC_NAMESPACE_IMPL_START
pcover expand(F, R, nonsparse)
INOUT pcover F;
IN pcover R;
IN bool nonsparse;
{
register pcube last, p;
pcube RAISE, FREESET, INIT_LOWER, SUPER_CUBE, OVEREXPANDED_CUBE;
int var, num_covered;
bool change;
if (use_random_order)
F = random_order(F);
else
F = mini_sort(F, ascend);
RAISE = new_cube();
FREESET = new_cube();
INIT_LOWER = new_cube();
SUPER_CUBE = new_cube();
OVEREXPANDED_CUBE = new_cube();
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]);
foreach_set(F, last, p) {
RESET(p, COVERED);
RESET(p, NONESSEN);
}
foreach_set(F, last, p) {
if (! TESTP(p, PRIME) && ! TESTP(p, COVERED)) {
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);
if (num_covered == 0 && ! setp_equal(p, OVEREXPANDED_CUBE)) {
SET(p, NONESSEN);
}
}
}
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;
}
void expand1(BB, CC, RAISE, FREESET, OVEREXPANDED_CUBE, SUPER_CUBE,
INIT_LOWER, num_covered, c)
pcover BB;
pcover CC;
pcube RAISE;
pcube FREESET;
pcube OVEREXPANDED_CUBE;
pcube SUPER_CUBE;
pcube INIT_LOWER;
int *num_covered;
pcube c;
{
int bestindex;
if (debug & EXPAND1)
printf("\nEXPAND1: \t%s\n", pc1(c));
SET(c, PRIME);
setup_BB_CC(BB, CC);
*num_covered = 0;
(void) set_copy(SUPER_CUBE, c);
(void) set_copy(RAISE, c);
(void) set_diff(FREESET, cube.fullset, RAISE);
if (! setp_empty(INIT_LOWER)) {
(void) set_diff(FREESET, FREESET, INIT_LOWER);
elim_lowering(BB, CC, RAISE, FREESET);
}
essen_parts(BB, CC, RAISE, FREESET);
(void) set_or(OVEREXPANDED_CUBE, RAISE, FREESET);
if (CC->active_count > 0) {
select_feasible(BB, CC, RAISE, FREESET, SUPER_CUBE, num_covered);
}
while (CC->active_count > 0) {
bestindex = most_frequent(CC, FREESET);
set_insert(RAISE, bestindex);
set_remove(FREESET, bestindex);
essen_parts(BB, CC, RAISE, FREESET);
}
while (BB->active_count > 0) {
mincov(BB, RAISE, FREESET);
}
(void) set_or(RAISE, RAISE, FREESET);
}
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<last;w++){x=p[w]&r[w];if((x=~(x|x>>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;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(p[w]&r[
w]&mask[w])goto nextvar;if(++dist>1)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);
elim_lowering(BB, CC, RAISE, FREESET);
}
if (debug & EXPAND1)
printf("ESSEN_PARTS:\tRAISE=%s FREESET=%s\n", pc1(RAISE), pc2(FREESET));
}
void essen_raising(BB, RAISE, FREESET)
register pcover BB;
pcube RAISE, FREESET;
{
register pcube last, p, xraise = cube.temp[0];
(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);
(void) set_diff(FREESET, FREESET, xraise);
if (debug & EXPAND1)
printf("ESSEN_RAISING:\tRAISE=%s FREESET=%s\n",
pc1(RAISE), pc2(FREESET));
}
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;
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<lastw;w++){x=p[w]
&r[w];if(~(x|x>>1)&DISJOINT)goto false;}}}{register int w,var,lastw;register
pcube mask;for(var=cube.num_binary_vars;var<cube.num_vars;var++){mask=cube.
var_mask[var];lastw=cube.last_word[var];for(w=cube.first_word[var];w<=lastw;w++)
if(p[w]&r[w]&mask[w])goto nextvar;goto false;nextvar:;}}continue;false:
#endif
BB->active_count--, RESET(p, ACTIVE);
}
if (CC != (pcover) NULL) {
foreach_active_set(CC, last, p) {
#ifdef NO_INLINE
if (! setp_implies(p, r))
#else
INLINEsetp_implies(p, r, goto false1);
continue;
false1:
#endif
CC->active_count--, RESET(p, ACTIVE);
}
}
}
int most_frequent(CC, FREESET)
pcover CC;
pcube FREESET;
{
register int i, best_part, best_count, *count;
register pset p, last;
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);
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;
}
void setup_BB_CC(BB, CC)
register pcover BB, CC;
{
register pcube p, last;
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);
}
}
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;
register pcube bestfeas = NULL; register pcube *feas;
register int i, j;
pcube *feas_new_lower;
int bestcount, bestsize, count, size, numfeas, lastfeas;
pcover new_lower;
feas = ALLOC(pcube, CC->active_count);
numfeas = 0;
foreach_active_set(CC, last, p)
feas[numfeas++] = p;
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:
essen_raising(BB, RAISE, FREESET);
lastfeas = numfeas;
numfeas = 0;
for(i = 0; i < lastfeas; i++) {
p = feas[i];
if (TESTP(p, ACTIVE)) {
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);
} else if (feasibly_covered(BB,p,RAISE,feas_new_lower[numfeas])) {
feas[numfeas] = p;
numfeas++;
}
}
}
if (debug & EXPAND1)
printf("SELECT_FEASIBLE: started with %d pfcc, ended with %d fcc\n",
lastfeas, numfeas);
if (numfeas == 0) {
FREE(feas);
FREE(feas_new_lower);
free_cover(new_lower);
return;
}
bestcount = 0;
bestsize = 9999;
for(i = 0; i < numfeas; i++) {
size = set_dist(feas[i], FREESET);
count = 0;
#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;
}
}
(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;
}
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<last;w++){x=p[w]&r[w];if((x=~(x|x>>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;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(p[w]&r[
w]&mask[w])goto nextvar;if(++dist>1)goto exit_if;nextvar:;}}
#endif
if (dist == 0)
return FALSE;
else
(void) force_lower(new_lower, p, r);
exit_if: ;
}
return TRUE;
}
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, (pcover) NULL, RAISE, FREESET);
#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);
}
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);
(void) set_or(RAISE, RAISE, set_diff(xraise, FREESET, xlower));
(void) set_copy(FREESET, cube.emptyset);
BB->active_count = 0;
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);
set_insert(RAISE, most_frequent( (pcover) NULL, FREESET));
(void) set_diff(FREESET, FREESET, RAISE);
essen_parts(BB, (pcover) NULL, RAISE, FREESET);
return;
#endif
}
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;
}
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 {
(void) set_copy(RAISE, p);
(void) set_diff(FREESET, cube.fullset, RAISE);
setup_BB_CC(R, (pcover) NULL);
essen_parts(R, (pcover) NULL, RAISE, FREESET);
B1 = find_all_primes(R, RAISE, FREESET);
Fall_primes = sf_append(Fall_primes, B1);
}
}
set_free(RAISE);
set_free(FREESET);
return Fall_primes;
}
ABC_NAMESPACE_IMPL_END