blob: aaa6114570d418c29195c67c3ecebe421169a79f [file] [log] [blame]
/*
* 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;
}