[buddy] introduce a bdd_satoneshortest() function
* src/bddop.c, src/bddx.h: Introduce this function. * src/bddtest.cxx: Add some short tests.
This commit is contained in:
parent
830f68b3b9
commit
5a0fbf6cb9
3 changed files with 215 additions and 0 deletions
|
|
@ -61,6 +61,8 @@
|
||||||
#define CACHEID_SUPPORT 0x6
|
#define CACHEID_SUPPORT 0x6
|
||||||
#define CACHEID_IMPLIES 0x7
|
#define CACHEID_IMPLIES 0x7
|
||||||
#define CACHEID_COMMON 0x8
|
#define CACHEID_COMMON 0x8
|
||||||
|
#define CACHEID_SHORTDIST 0x9
|
||||||
|
#define CACHEID_SHORTBDD 0xA
|
||||||
|
|
||||||
/* Hash value modifiers for replace/compose */
|
/* Hash value modifiers for replace/compose */
|
||||||
#define CACHEID_REPLACE 0x0
|
#define CACHEID_REPLACE 0x0
|
||||||
|
|
@ -182,6 +184,8 @@ static int varset2svartable(BDD);
|
||||||
#define PATHCOUHASH(r) (r)
|
#define PATHCOUHASH(r) (r)
|
||||||
#define SUPPORTHASH(r) (PAIR(r,CACHEID_SUPPORT))
|
#define SUPPORTHASH(r) (PAIR(r,CACHEID_SUPPORT))
|
||||||
#define APPEXHASH(l,r,op) (PAIR(l,r))
|
#define APPEXHASH(l,r,op) (PAIR(l,r))
|
||||||
|
#define SHORTDISTHASH(l,rev) (TRIPLE(l,rev,CACHEID_SHORTDIST))
|
||||||
|
#define SHORTBDDHASH(l,rev) (TRIPLE(l,rev,CACHEID_SHORTBDD))
|
||||||
|
|
||||||
#ifndef M_LN2
|
#ifndef M_LN2
|
||||||
#define M_LN2 0.69314718055994530942
|
#define M_LN2 0.69314718055994530942
|
||||||
|
|
@ -3078,6 +3082,153 @@ static BDD satoneset_rec(BDD r, BDD var)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Compute the smallest distance associated to a satisfying path of f,
|
||||||
|
but without actually building the corresponding cube. This is done
|
||||||
|
by computing the distance recursively for all sub BDDs, and storing
|
||||||
|
those in a hashtable, with the intention of sharing that across
|
||||||
|
all calls of bdd_satoneshortest with the same weights.
|
||||||
|
|
||||||
|
The hash table used for cache stores triples of the form (bdd, rev,
|
||||||
|
dist) where dist is the distance for bdd, and rev is incremented
|
||||||
|
everytime bdd_satoneshortest is called with a different set of
|
||||||
|
weights. One should therefore check that rev from the cache lookup
|
||||||
|
matches the current rev stored in shortest_rev. bdd_satoneshortest
|
||||||
|
is in charge of incrementing shortest_rev.
|
||||||
|
*/
|
||||||
|
static unsigned wlow_ref = 0;
|
||||||
|
static unsigned whigh_ref = 0;
|
||||||
|
static unsigned wdc_ref = 0;
|
||||||
|
static int shortest_rev = 0;
|
||||||
|
|
||||||
|
/* This computes the shortest distance, recursively.
|
||||||
|
Populating the cache. */
|
||||||
|
static unsigned satoneshortest_rec(BDD f)
|
||||||
|
{
|
||||||
|
if (ISONE(f))
|
||||||
|
return 0;
|
||||||
|
if (ISZERO(f))
|
||||||
|
return -1U;
|
||||||
|
int rev = shortest_rev;
|
||||||
|
BddCacheData *entry = BddCache_lookup(&misccache, SHORTDISTHASH(f,rev));
|
||||||
|
if (entry->i.a == f
|
||||||
|
&& entry->i.b == rev
|
||||||
|
&& entry->i.c == CACHEID_SHORTDIST)
|
||||||
|
{
|
||||||
|
#ifdef CACHESTATS
|
||||||
|
bddcachestats.opHit++;
|
||||||
|
#endif
|
||||||
|
return (unsigned) entry->i.res;
|
||||||
|
}
|
||||||
|
#ifdef CACHESTATS
|
||||||
|
bddcachestats.opMiss++;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int lv_next = LEVEL(f) + 1;
|
||||||
|
int low = LOW(f);
|
||||||
|
int lv_low = LEVEL(low);
|
||||||
|
unsigned dist_low = satoneshortest_rec(low);
|
||||||
|
if (dist_low != -1U)
|
||||||
|
dist_low += wlow_ref + wdc_ref * (lv_low - lv_next);
|
||||||
|
int high = HIGH(f);
|
||||||
|
int lv_high = LEVEL(high);
|
||||||
|
unsigned dist_high = satoneshortest_rec(high);
|
||||||
|
if (dist_high != -1U)
|
||||||
|
dist_high += whigh_ref + wdc_ref * (lv_high - lv_next);
|
||||||
|
|
||||||
|
if (dist_high < dist_low)
|
||||||
|
dist_low = dist_high;
|
||||||
|
|
||||||
|
entry->i.a = f;
|
||||||
|
entry->i.b = rev;
|
||||||
|
entry->i.c = CACHEID_SHORTDIST;
|
||||||
|
entry->i.res = (int) dist_low;
|
||||||
|
return dist_low;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This computes the BDD for the shortest distance, recursively.
|
||||||
|
It calls satoneshortest_rec again, but this should be fast thanks to
|
||||||
|
the cache.
|
||||||
|
*/
|
||||||
|
static bdd bdd_satoneshortest_rec(BDD f)
|
||||||
|
{
|
||||||
|
if (ISONE(f))
|
||||||
|
return bddtrue;
|
||||||
|
if (ISZERO(f))
|
||||||
|
return bddfalse;
|
||||||
|
|
||||||
|
int rev = shortest_rev;
|
||||||
|
BddCacheData *entry = BddCache_lookup(&misccache, SHORTBDDHASH(f,rev));
|
||||||
|
if (entry->i.a == f
|
||||||
|
&& entry->i.b == rev
|
||||||
|
&& entry->i.c == CACHEID_SHORTDIST)
|
||||||
|
{
|
||||||
|
#ifdef CACHESTATS
|
||||||
|
bddcachestats.opHit++;
|
||||||
|
#endif
|
||||||
|
return entry->i.res;
|
||||||
|
}
|
||||||
|
#ifdef CACHESTATS
|
||||||
|
bddcachestats.opMiss++;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int lv = LEVEL(f);
|
||||||
|
int lv_next = lv + 1;
|
||||||
|
int low = LOW(f);
|
||||||
|
int lv_low = LEVEL(low);
|
||||||
|
unsigned dist_low = satoneshortest_rec(low);
|
||||||
|
if (dist_low != -1U)
|
||||||
|
dist_low += wlow_ref + wdc_ref * (lv_low - lv_next);
|
||||||
|
|
||||||
|
int high = HIGH(f);
|
||||||
|
int lv_high = LEVEL(high);
|
||||||
|
unsigned dist_high = satoneshortest_rec(high);
|
||||||
|
if (dist_high != -1U)
|
||||||
|
dist_high += whigh_ref + wdc_ref * (lv_high - lv_next);
|
||||||
|
|
||||||
|
bdd res;
|
||||||
|
if (dist_high < dist_low)
|
||||||
|
{
|
||||||
|
res = bdd_satoneshortest_rec(high);
|
||||||
|
res = PUSHREF(bdd_makenode(lv, 0, res));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = bdd_satoneshortest_rec(low);
|
||||||
|
res = PUSHREF(bdd_makenode(lv, res, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
entry->i.a = f;
|
||||||
|
entry->i.b = rev;
|
||||||
|
entry->i.c = CACHEID_SHORTBDD;
|
||||||
|
entry->i.res = res;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
return a conjunction representing a satisfying path of f, chosen
|
||||||
|
among all satisfying paths to minimize the sum of weights given for
|
||||||
|
positive variables (whigh), negative variables (wlow), and don't care
|
||||||
|
variables (wdc = Weight of Don't Care).
|
||||||
|
*/
|
||||||
|
BDD bdd_satoneshortest(BDD f, unsigned wlow, unsigned whigh, unsigned wdc)
|
||||||
|
{
|
||||||
|
if (wlow != wlow_ref || whigh != whigh_ref || wdc != wdc_ref)
|
||||||
|
{
|
||||||
|
wlow_ref = wlow;
|
||||||
|
whigh_ref = whigh;
|
||||||
|
wdc_ref = wdc;
|
||||||
|
++shortest_rev;
|
||||||
|
}
|
||||||
|
bdd_disable_reorder();
|
||||||
|
INITREF;
|
||||||
|
bdd res = bdd_satoneshortest_rec(f);
|
||||||
|
bdd_enable_reorder();
|
||||||
|
checkresize();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*=== EXACTLY ONE SATISFYING VARIABLE ASSIGNMENT =======================*/
|
/*=== EXACTLY ONE SATISFYING VARIABLE ASSIGNMENT =======================*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,60 @@ void testBvecIte()
|
||||||
ERROR("Bit 2 failed.");
|
ERROR("Bit 2 failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testShortest()
|
||||||
|
{
|
||||||
|
cout << "Testing bdd_satoneshortest()\n";
|
||||||
|
|
||||||
|
bdd a = bdd_ithvar(0);
|
||||||
|
bdd b = bdd_ithvar(1);
|
||||||
|
bdd c = bdd_ithvar(2);
|
||||||
|
bdd d = bdd_ithvar(3);
|
||||||
|
|
||||||
|
bdd cube1 = a&c&!d;
|
||||||
|
bdd cube2 = a&!c&d;
|
||||||
|
bdd cube3 = !a&b&c&!d;
|
||||||
|
bdd cube4 = !a&!b&d;
|
||||||
|
|
||||||
|
bdd f = cube1 | cube2 | cube3 | cube4 ;
|
||||||
|
|
||||||
|
// avoid don't care at all cost, prefer negative
|
||||||
|
bdd res = bdd_satoneshortest(f, 0, 1, 4);
|
||||||
|
if (res != cube3)
|
||||||
|
ERROR("shortest 0 1 4 failed");
|
||||||
|
|
||||||
|
// avoid don't care at all cost, prefer positive
|
||||||
|
res = bdd_satoneshortest(f, 1, 0, 4);
|
||||||
|
if (res != cube3)
|
||||||
|
ERROR("shortest 1 0 4 failed");
|
||||||
|
|
||||||
|
// avoid negative at all cost, prefer positive
|
||||||
|
res = bdd_satoneshortest(f, 4, 0, 1);
|
||||||
|
if (res != cube2)
|
||||||
|
ERROR("shortest 4 0 1 failed");
|
||||||
|
|
||||||
|
// avoid negative at all cost, prefer don't care
|
||||||
|
res = bdd_satoneshortest(f, 4, 1, 0);
|
||||||
|
if (res != cube2)
|
||||||
|
ERROR("shortest 4 1 0 failed");
|
||||||
|
|
||||||
|
// avoid positive at all cost, prefer don't care
|
||||||
|
res = bdd_satoneshortest(f, 1, 4, 0);
|
||||||
|
if (res != cube4)
|
||||||
|
ERROR("shortest 1 4 0 failed");
|
||||||
|
|
||||||
|
// avoid positive at all cost, prefer negative
|
||||||
|
res = bdd_satoneshortest(f, 0, 4, 1);
|
||||||
|
if (res != cube4)
|
||||||
|
ERROR("shortest 0 4 1 failed");
|
||||||
|
|
||||||
|
res = bdd_satoneshortest(bddfalse, 1, 2, 3);
|
||||||
|
if (res != bddfalse)
|
||||||
|
ERROR("shortest bddfalse failed");
|
||||||
|
|
||||||
|
res = bdd_satoneshortest(bddtrue, 1, 2, 3);
|
||||||
|
if (res != bddtrue)
|
||||||
|
ERROR("shortest bddtrue failed");
|
||||||
|
}
|
||||||
|
|
||||||
int main(int ac, char** av)
|
int main(int ac, char** av)
|
||||||
{
|
{
|
||||||
|
|
@ -105,6 +159,7 @@ int main(int ac, char** av)
|
||||||
|
|
||||||
testSupport();
|
testSupport();
|
||||||
testBvecIte();
|
testBvecIte();
|
||||||
|
testShortest();
|
||||||
|
|
||||||
bdd_done();
|
bdd_done();
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -379,6 +379,7 @@ BUDDY_API BDD bdd_support(BDD);
|
||||||
BUDDY_API BDD bdd_satone(BDD);
|
BUDDY_API BDD bdd_satone(BDD);
|
||||||
BUDDY_API BDD bdd_satoneset(BDD, BDD, BDD);
|
BUDDY_API BDD bdd_satoneset(BDD, BDD, BDD);
|
||||||
BUDDY_API BDD bdd_fullsatone(BDD);
|
BUDDY_API BDD bdd_fullsatone(BDD);
|
||||||
|
BUDDY_API BDD bdd_satoneshortest(BDD, unsigned, unsigned, unsigned);
|
||||||
BUDDY_API BDD bdd_satprefix(BDD *);
|
BUDDY_API BDD bdd_satprefix(BDD *);
|
||||||
BUDDY_API void bdd_allsat(BDD r, bddallsathandler handler);
|
BUDDY_API void bdd_allsat(BDD r, bddallsathandler handler);
|
||||||
BUDDY_API double bdd_satcount(BDD);
|
BUDDY_API double bdd_satcount(BDD);
|
||||||
|
|
@ -635,6 +636,8 @@ protected:
|
||||||
friend bdd bdd_satone(const bdd &);
|
friend bdd bdd_satone(const bdd &);
|
||||||
friend bdd bdd_satoneset(const bdd &, const bdd &, const bdd &);
|
friend bdd bdd_satoneset(const bdd &, const bdd &, const bdd &);
|
||||||
friend bdd bdd_fullsatone(const bdd &);
|
friend bdd bdd_fullsatone(const bdd &);
|
||||||
|
friend bdd bdd_satoneshortest(const bdd &,
|
||||||
|
unsigned, unsigned, unsigned);
|
||||||
friend bdd bdd_satprefix(bdd &);
|
friend bdd bdd_satprefix(bdd &);
|
||||||
friend void bdd_allsat(const bdd &r, bddallsathandler handler);
|
friend void bdd_allsat(const bdd &r, bddallsathandler handler);
|
||||||
friend void bdd_allsat(const bdd &r, bddallsathandler_old handler);
|
friend void bdd_allsat(const bdd &r, bddallsathandler_old handler);
|
||||||
|
|
@ -867,6 +870,12 @@ inline bdd bdd_satoneset(const bdd &r, const bdd &var, const bdd &pol)
|
||||||
inline bdd bdd_fullsatone(const bdd &r)
|
inline bdd bdd_fullsatone(const bdd &r)
|
||||||
{ return bdd_fullsatone(r.root); }
|
{ return bdd_fullsatone(r.root); }
|
||||||
|
|
||||||
|
inline bdd bdd_satoneshortest(const bdd &r, unsigned wlow,
|
||||||
|
unsigned whigh, unsigned wdc)
|
||||||
|
{
|
||||||
|
return bdd_satoneshortest(r.root, wlow, whigh, wdc);
|
||||||
|
}
|
||||||
|
|
||||||
inline bdd bdd_satprefix(bdd &r)
|
inline bdd bdd_satprefix(bdd &r)
|
||||||
{ int ro = r.root; bdd res = bdd_satprefix(&ro); r = bdd(ro); return res; }
|
{ int ro = r.root; bdd res = bdd_satprefix(&ro); r = bdd(ro); return res; }
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue