mirror of https://github.com/YosysHQ/abc.git
264 lines
7.3 KiB
C
264 lines
7.3 KiB
C
/*
|
||
* Revision Control Information
|
||
*
|
||
* $Source$
|
||
* $Author$
|
||
* $Revision$
|
||
* $Date$
|
||
*
|
||
*/
|
||
/*
|
||
module: reduce.c
|
||
purpose: Perform the Espresso-II reduction step
|
||
|
||
Reduction is a technique used to explore larger regions of the
|
||
optimization space. We replace each cube of F with a smaller
|
||
cube while still maintaining a cover of the same logic function.
|
||
*/
|
||
|
||
#include "espresso.h"
|
||
|
||
ABC_NAMESPACE_IMPL_START
|
||
|
||
|
||
static bool toggle = TRUE;
|
||
|
||
|
||
/*
|
||
reduce -- replace each cube in F with its reduction
|
||
|
||
The reduction of a cube is the smallest cube contained in the cube
|
||
which can replace the cube in the original cover without changing
|
||
the cover. This is equivalent to the super cube of all of the
|
||
essential points in the cube. This can be computed directly.
|
||
|
||
The problem is that the order in which the cubes are reduced can
|
||
greatly affect the final result. We alternate between two ordering
|
||
strategies:
|
||
|
||
(1) Order the cubes in ascending order of distance from the
|
||
largest cube breaking ties by ordering cubes of equal distance
|
||
in descending order of size (sort_reduce)
|
||
|
||
(2) Order the cubes in descending order of the inner-product of
|
||
the cube and the column sums (mini_sort)
|
||
|
||
The real workhorse of this section is the routine SCCC which is
|
||
used to find the Smallest Cube Containing the Complement of a cover.
|
||
Reduction as proposed by Espresso-II takes a cube and computes its
|
||
maximal reduction as the intersection between the cube and the
|
||
smallest cube containing the complement of (F u D - {c}) cofactored
|
||
against c.
|
||
|
||
As usual, the unate-recursive paradigm is used to compute SCCC.
|
||
The SCCC of a unate cover is trivial to compute, and thus we perform
|
||
Shannon Cofactor expansion attempting to drive the cover to be unate
|
||
as fast as possible.
|
||
*/
|
||
|
||
pcover reduce(F, D)
|
||
INOUT pcover F;
|
||
IN pcover D;
|
||
{
|
||
register pcube last, p, cunder, *FD;
|
||
|
||
/* Order the cubes */
|
||
if (use_random_order)
|
||
F = random_order(F);
|
||
else {
|
||
F = toggle ? sort_reduce(F) : mini_sort(F, descend);
|
||
toggle = ! toggle;
|
||
}
|
||
|
||
/* Try to reduce each cube */
|
||
FD = cube2list(F, D);
|
||
foreach_set(F, last, p) {
|
||
cunder = reduce_cube(FD, p); /* reduce the cube */
|
||
if (setp_equal(cunder, p)) { /* see if it actually did */
|
||
SET(p, ACTIVE); /* cube remains active */
|
||
SET(p, PRIME); /* cube remains prime ? */
|
||
} else {
|
||
if (debug & REDUCE) {
|
||
printf("REDUCE: %s to %s %s\n",
|
||
pc1(p), pc2(cunder), print_time(ptime()));
|
||
}
|
||
set_copy(p, cunder); /* save reduced version */
|
||
RESET(p, PRIME); /* cube is no longer prime */
|
||
if (setp_empty(cunder))
|
||
RESET(p, ACTIVE); /* if null, kill the cube */
|
||
else
|
||
SET(p, ACTIVE); /* cube is active */
|
||
}
|
||
free_cube(cunder);
|
||
}
|
||
free_cubelist(FD);
|
||
|
||
/* Delete any cubes of F which reduced to the empty cube */
|
||
return sf_inactive(F);
|
||
}
|
||
|
||
/* reduce_cube -- find the maximal reduction of a cube */
|
||
pcube reduce_cube(FD, p)
|
||
IN pcube *FD, p;
|
||
{
|
||
pcube cunder;
|
||
|
||
cunder = sccc(cofactor(FD, p));
|
||
return set_and(cunder, cunder, p);
|
||
}
|
||
|
||
|
||
/* sccc -- find Smallest Cube Containing the Complement of a cover */
|
||
pcube sccc(T)
|
||
INOUT pcube *T; /* T will be disposed of */
|
||
{
|
||
pcube r;
|
||
register pcube cl, cr;
|
||
register int best;
|
||
static int sccc_level = 0;
|
||
|
||
if (debug & REDUCE1) {
|
||
debug_print(T, "SCCC", sccc_level++);
|
||
}
|
||
|
||
if (sccc_special_cases(T, &r) == MAYBE) {
|
||
cl = new_cube();
|
||
cr = new_cube();
|
||
best = binate_split_select(T, cl, cr, REDUCE1);
|
||
r = sccc_merge(sccc(scofactor(T, cl, best)),
|
||
sccc(scofactor(T, cr, best)), cl, cr);
|
||
free_cubelist(T);
|
||
}
|
||
|
||
if (debug & REDUCE1)
|
||
printf("SCCC[%d]: result is %s\n", --sccc_level, pc1(r));
|
||
return r;
|
||
}
|
||
|
||
|
||
pcube sccc_merge(left, right, cl, cr)
|
||
INOUT register pcube left, right; /* will be disposed of ... */
|
||
INOUT register pcube cl, cr; /* will be disposed of ... */
|
||
{
|
||
INLINEset_and(left, left, cl);
|
||
INLINEset_and(right, right, cr);
|
||
INLINEset_or(left, left, right);
|
||
free_cube(right);
|
||
free_cube(cl);
|
||
free_cube(cr);
|
||
return left;
|
||
}
|
||
|
||
|
||
/*
|
||
sccc_cube -- find the smallest cube containing the complement of a cube
|
||
|
||
By DeMorgan's law and the fact that the smallest cube containing a
|
||
cover is the "or" of the positional cubes, it is simple to see that
|
||
the SCCC is the universe if the cube has more than two active
|
||
variables. If there is only a single active variable, then the
|
||
SCCC is merely the bitwise complement of the cube in that
|
||
variable. A last special case is no active variables, in which
|
||
case the SCCC is empty.
|
||
|
||
This is "anded" with the incoming cube result.
|
||
*/
|
||
pcube sccc_cube(result, p)
|
||
register pcube result, p;
|
||
{
|
||
register pcube temp=cube.temp[0], mask;
|
||
int var;
|
||
|
||
if ((var = cactive(p)) >= 0) {
|
||
mask = cube.var_mask[var];
|
||
INLINEset_xor(temp, p, mask);
|
||
INLINEset_and(result, result, temp);
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/*
|
||
* sccc_special_cases -- check the special cases for sccc
|
||
*/
|
||
|
||
bool sccc_special_cases(T, result)
|
||
INOUT pcube *T; /* will be disposed if answer is determined */
|
||
OUT pcube *result; /* returned only if answer determined */
|
||
{
|
||
register pcube *T1, p, temp = cube.temp[1], ceil, cof = T[0];
|
||
pcube *A, *B;
|
||
|
||
/* empty cover => complement is universe => SCCC is universe */
|
||
if (T[2] == NULL) {
|
||
*result = set_save(cube.fullset);
|
||
free_cubelist(T);
|
||
return TRUE;
|
||
}
|
||
|
||
/* row of 1's => complement is empty => SCCC is empty */
|
||
for(T1 = T+2; (p = *T1++) != NULL; ) {
|
||
if (full_row(p, cof)) {
|
||
*result = new_cube();
|
||
free_cubelist(T);
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
/* Collect column counts, determine unate variables, etc. */
|
||
massive_count(T);
|
||
|
||
/* If cover is unate (or single cube), apply simple rules to find SCCCU */
|
||
if (cdata.vars_unate == cdata.vars_active || T[3] == NULL) {
|
||
*result = set_save(cube.fullset);
|
||
for(T1 = T+2; (p = *T1++) != NULL; ) {
|
||
(void) sccc_cube(*result, set_or(temp, p, cof));
|
||
}
|
||
free_cubelist(T);
|
||
return TRUE;
|
||
}
|
||
|
||
/* Check for column of 0's (which can be easily factored( */
|
||
ceil = set_save(cof);
|
||
for(T1 = T+2; (p = *T1++) != NULL; ) {
|
||
INLINEset_or(ceil, ceil, p);
|
||
}
|
||
if (! setp_equal(ceil, cube.fullset)) {
|
||
*result = sccc_cube(set_save(cube.fullset), ceil);
|
||
if (setp_equal(*result, cube.fullset)) {
|
||
free_cube(ceil);
|
||
} else {
|
||
*result = sccc_merge(sccc(cofactor(T,ceil)),
|
||
set_save(cube.fullset), ceil, *result);
|
||
}
|
||
free_cubelist(T);
|
||
return TRUE;
|
||
}
|
||
free_cube(ceil);
|
||
|
||
/* Single active column at this point => tautology => SCCC is empty */
|
||
if (cdata.vars_active == 1) {
|
||
*result = new_cube();
|
||
free_cubelist(T);
|
||
return TRUE;
|
||
}
|
||
|
||
/* Check for components */
|
||
if (cdata.var_zeros[cdata.best] < CUBELISTSIZE(T)/2) {
|
||
if (cubelist_partition(T, &A, &B, debug & REDUCE1) == 0) {
|
||
return MAYBE;
|
||
} else {
|
||
free_cubelist(T);
|
||
*result = sccc(A);
|
||
ceil = sccc(B);
|
||
(void) set_and(*result, *result, ceil);
|
||
set_free(ceil);
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
/* Not much we can do about it */
|
||
return MAYBE;
|
||
}
|
||
ABC_NAMESPACE_IMPL_END
|
||
|