[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:
Alexandre Duret-Lutz 2021-06-16 22:33:22 +02:00 committed by Florian Renkin
parent 830f68b3b9
commit 5a0fbf6cb9
3 changed files with 215 additions and 0 deletions

View file

@ -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 =======================*/
/* /*

View file

@ -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;

View file

@ -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; }