#include "espresso.h"
ABC_NAMESPACE_IMPL_START
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;
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);
}
skip_make_sparse = FALSE;
(void) set_phase(PLA);
minimize(PLA);
}
void repeated_phase_assignment(PLA)
pPLA PLA;
{
int i;
pcube phase;
for(i = 0; i < cube.part_size[cube.output]; i++) {
phase = find_phase(PLA, i, PLA->phase);
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);
}
}
pcube find_phase(PLA, first_output, phase1)
pPLA PLA;
int first_output;
pcube phase1;
{
pcube phase;
pPLA PLA1;
phase = set_save(cube.fullset);
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(PLA1);
EXEC_S(PLA1->F = opo(phase, PLA1->F, PLA1->D, PLA1->R, first_output),
"OPO ", PLA1->F);
free_PLA(PLA1);
setdown_cube();
cube.part_size[cube.output] -=
(cube.part_size[cube.output] - first_output) / 2;
cube_setup();
return phase;
}
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;
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);
}
}
}
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);
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);
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);
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#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];
temp = sf_new(2, T->count);
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);
}
}
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#endif
void 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;
setdown_cube();
cube.part_size[cube.output] += offset;
cube_setup();
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);
}
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++) {
F = sf_save(PLA->F);
D = sf_save(PLA->D);
R = sf_save(PLA->R);
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;
}
(void) set_phase(PLA);
printf("# phase is %s\n", pc1(PLA->phase));
summary = TRUE;
minimize(PLA);
if (PLA->F->count < best_F->count) {
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 {
free_cover(PLA->F);
free_cover(PLA->D);
free_cover(PLA->R);
}
set_free(PLA->phase);
PLA->F = F;
PLA->D = D;
PLA->R = R;
}
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);
}
}
ABC_NAMESPACE_IMPL_END