spot/buddy/src/bddop.c
2003-05-22 12:09:20 +00:00

2832 lines
66 KiB
C

/*========================================================================
Copyright (C) 1996-2002 by Jorn Lind-Nielsen
All rights reserved
Permission is hereby granted, without written agreement and without
license or royalty fees, to use, reproduce, prepare derivative
works, distribute, and display this software and its documentation
for any purpose, provided that (1) the above copyright notice and
the following two paragraphs appear in all copies of the source code
and (2) redistributions, including without limitation binaries,
reproduce these notices in the supporting documentation. Substantial
modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided
that the new terms are clearly indicated in all files where they apply.
IN NO EVENT SHALL JORN LIND-NIELSEN, OR DISTRIBUTORS OF THIS
SOFTWARE BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS
SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE AUTHORS OR ANY OF THE
ABOVE PARTIES HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
JORN LIND-NIELSEN SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO
OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
========================================================================*/
/*************************************************************************
$Header: /Volumes/CVS/repository/spot/spot/buddy/src/bddop.c,v 1.6 2003/05/22 12:09:20 aduret Exp $
FILE: bddop.c
DESCR: BDD operators
AUTH: Jorn Lind
DATE: (C) nov 1997
*************************************************************************/
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <assert.h>
#include "kernel.h"
#include "cache.h"
/* Hash value modifiers to distinguish between entries in misccache */
#define CACHEID_CONSTRAIN 0x0
#define CACHEID_RESTRICT 0x1
#define CACHEID_SATCOU 0x2
#define CACHEID_SATCOULN 0x3
#define CACHEID_PATHCOU 0x4
/* Hash value modifiers for replace/compose */
#define CACHEID_REPLACE 0x0
#define CACHEID_COMPOSE 0x1
#define CACHEID_VECCOMPOSE 0x2
/* Hash value modifiers for quantification */
#define CACHEID_EXIST 0x0
#define CACHEID_FORALL 0x1
#define CACHEID_UNIQUE 0x2
#define CACHEID_APPEX 0x3
#define CACHEID_APPAL 0x4
#define CACHEID_APPUN 0x5
/* Number of boolean operators */
#define OPERATOR_NUM 11
/* Operator results - entry = left<<1 | right (left,right in {0,1}) */
static int oprres[OPERATOR_NUM][4] =
{ {0,0,0,1}, /* and ( & ) */
{0,1,1,0}, /* xor ( ^ ) */
{0,1,1,1}, /* or ( | ) */
{1,1,1,0}, /* nand */
{1,0,0,0}, /* nor */
{1,1,0,1}, /* implication ( >> ) */
{1,0,0,1}, /* bi-implication */
{0,0,1,0}, /* difference /greater than ( - ) ( > ) */
{0,1,0,0}, /* less than ( < ) */
{1,0,1,1}, /* inverse implication ( << ) */
{1,1,0,0} /* not ( ! ) */
};
/* Variables needed for the operators */
static int applyop; /* Current operator for apply */
static int appexop; /* Current operator for appex */
static int appexid; /* Current cache id for appex */
static int quantid; /* Current cache id for quantifications */
static int *quantvarset; /* Current variable set for quant. */
static int quantvarsetID; /* Current id used in quantvarset */
static int quantlast; /* Current last variable to be quant. */
static int replaceid; /* Current cache id for replace */
static int *replacepair; /* Current replace pair */
static int replacelast; /* Current last var. level to replace */
static int composelevel; /* Current variable used for compose */
static int miscid; /* Current cache id for other results */
static int *varprofile; /* Current variable profile */
static int supportID; /* Current ID (true value) for support */
static int supportMin; /* Min. used level in support calc. */
static int supportMax; /* Max. used level in support calc. */
static int* supportSet; /* The found support set */
static BddCache applycache; /* Cache for apply results */
static BddCache itecache; /* Cache for ITE results */
static BddCache quantcache; /* Cache for exist/forall results */
static BddCache appexcache; /* Cache for appex/appall results */
static BddCache replacecache; /* Cache for replace results */
static BddCache misccache; /* Cache for other results */
static int cacheratio;
static BDD satPolarity;
static int firstReorder; /* Used instead of local variable in order
to avoid compiler warning about 'first'
being clobbered by setjmp */
static char* allsatProfile; /* Variable profile for bdd_allsat() */
static bddallsathandler allsatHandler; /* Callback handler for bdd_allsat() */
extern bddCacheStat bddcachestats;
/* Internal prototypes */
static BDD not_rec(BDD);
static BDD apply_rec(BDD, BDD);
static BDD ite_rec(BDD, BDD, BDD);
static int simplify_rec(BDD, BDD);
static int quant_rec(int);
static int appquant_rec(int, int);
static int restrict_rec(int);
static BDD constrain_rec(BDD, BDD);
static BDD replace_rec(BDD);
static BDD bdd_correctify(int, BDD, BDD);
static BDD compose_rec(BDD, BDD);
static BDD veccompose_rec(BDD);
static void support_rec(int, int*);
static BDD satone_rec(BDD);
static BDD satoneset_rec(BDD, BDD);
static int fullsatone_rec(int);
static void allsat_rec(BDD r);
static double satcount_rec(int);
static double satcountln_rec(int);
static void varprofile_rec(int);
static double bdd_pathcount_rec(BDD);
static int varset2vartable(BDD);
static int varset2svartable(BDD);
/* Hashvalues */
#define NOTHASH(r) (r)
#define APPLYHASH(l,r,op) (TRIPLE(l,r,op))
#define ITEHASH(f,g,h) (TRIPLE(f,g,h))
#define RESTRHASH(r,var) (PAIR(r,var))
#define CONSTRAINHASH(f,c) (PAIR(f,c))
#define QUANTHASH(r) (r)
#define REPLACEHASH(r) (r)
#define VECCOMPOSEHASH(f) (f)
#define COMPOSEHASH(f,g) (PAIR(f,g))
#define SATCOUHASH(r) (r)
#define PATHCOUHASH(r) (r)
#define APPEXHASH(l,r,op) (PAIR(l,r))
#ifndef M_LN2
#define M_LN2 0.69314718055994530942
#endif
#define log1p(a) (log(1.0+a))
#define INVARSET(a) (quantvarset[a] == quantvarsetID) /* unsigned check */
#define INSVARSET(a) (abs(quantvarset[a]) == quantvarsetID) /* signed check */
/*************************************************************************
Setup and shutdown
*************************************************************************/
int bdd_operator_init(int cachesize)
{
if (BddCache_init(&applycache,cachesize) < 0)
return bdd_error(BDD_MEMORY);
if (BddCache_init(&itecache,cachesize) < 0)
return bdd_error(BDD_MEMORY);
if (BddCache_init(&quantcache,cachesize) < 0)
return bdd_error(BDD_MEMORY);
if (BddCache_init(&appexcache,cachesize) < 0)
return bdd_error(BDD_MEMORY);
if (BddCache_init(&replacecache,cachesize) < 0)
return bdd_error(BDD_MEMORY);
if (BddCache_init(&misccache,cachesize) < 0)
return bdd_error(BDD_MEMORY);
quantvarsetID = 0;
quantvarset = NULL;
cacheratio = 0;
supportSet = NULL;
return 0;
}
void bdd_operator_done(void)
{
if (quantvarset != NULL)
free(quantvarset);
BddCache_done(&applycache);
BddCache_done(&itecache);
BddCache_done(&quantcache);
BddCache_done(&appexcache);
BddCache_done(&replacecache);
BddCache_done(&misccache);
if (supportSet != NULL)
free(supportSet);
}
void bdd_operator_reset(void)
{
BddCache_reset(&applycache);
BddCache_reset(&itecache);
BddCache_reset(&quantcache);
BddCache_reset(&appexcache);
BddCache_reset(&replacecache);
BddCache_reset(&misccache);
}
void bdd_operator_varresize(void)
{
if (quantvarset != NULL)
free(quantvarset);
if ((quantvarset=NEW(int,bddvarnum)) == NULL)
bdd_error(BDD_MEMORY);
memset(quantvarset, 0, sizeof(int)*bddvarnum);
quantvarsetID = 0;
}
static void bdd_operator_noderesize(void)
{
if (cacheratio > 0)
{
int newcachesize = bddnodesize / cacheratio;
BddCache_resize(&applycache, newcachesize);
BddCache_resize(&itecache, newcachesize);
BddCache_resize(&quantcache, newcachesize);
BddCache_resize(&appexcache, newcachesize);
BddCache_resize(&replacecache, newcachesize);
BddCache_resize(&misccache, newcachesize);
}
}
/*************************************************************************
Other
*************************************************************************/
/*
NAME {* bdd\_setcacheratio *}
SECTION {* kernel *}
SHORT {* Sets the cache ratio for the operator caches *}
PROTO {* int bdd_setcacheratio(int r) *}
DESCR {* The ratio between the number of nodes in the nodetable
and the number of entries in the operator cachetables is called
the cache ratio. So a cache ratio of say, four, allocates one cache
entry for each four unique node entries. This value can be set with
{\tt bdd\_setcacheratio} to any positive value. When this is done
the caches are resized instantly to fit the new ratio.
The default is a fixed cache size determined at
initialization time. *}
RETURN {* The previous cache ratio or a negative number on error. *}
ALSO {* bdd\_init *}
*/
int bdd_setcacheratio(int r)
{
int old = cacheratio;
if (r <= 0)
return bdd_error(BDD_RANGE);
if (bddnodesize == 0)
return old;
cacheratio = r;
bdd_operator_noderesize();
return old;
}
/*************************************************************************
Operators
*************************************************************************/
static void checkresize(void)
{
if (bddresized)
bdd_operator_noderesize();
bddresized = 0;
}
/*=== BUILD A CUBE =====================================================*/
/*
NAME {* bdd\_buildcube *}
EXTRA {* bdd\_ibuildcube *}
SECTION {* operator *}
SHORT {* build a cube from an array of variables *}
PROTO {* BDD bdd_buildcube(int value, int width, BDD *var)
BDD bdd_ibuildcube(int value, int width, int *var)*}
DESCR {* This function builds a cube from the variables in {\tt
var}. It does so by interpreting the {\tt width} low order
bits of {\tt value} as a bit mask--a set bit indicates that the
variable should be added in it's positive form, and a cleared
bit the opposite. The most significant bits are encoded with
the first variables in {\tt var}. Consider as an example
the call {\tt bdd\_buildcube(0xB, 4, var)}. This corresponds
to the expression: $var[0] \conj \neg var[1] \conj var[2]
\conj var[3]$. The first version of the function takes an array
of BDDs, whereas the second takes an array of variable numbers
as used in {\tt bdd\_ithvar}. *}
RETURN {* The resulting cube *}
ALSO {* bdd\_ithvar, fdd\_ithvar *}
*/
BDD bdd_buildcube(int value, int width, BDD *variables)
{
BDD result = BDDONE;
int z;
for (z=0 ; z<width ; z++, value>>=1)
{
BDD tmp;
BDD v;
if (value & 0x1)
v = bdd_addref( variables[width-z-1] );
else
v = bdd_addref( bdd_not(variables[width-z-1]) );
bdd_addref(result);
tmp = bdd_apply(result,v,bddop_and);
bdd_delref(result);
bdd_delref(v);
result = tmp;
}
return result;
}
BDD bdd_ibuildcube(int value, int width, int *variables)
{
BDD result = BDDONE;
int z;
for (z=0 ; z<width ; z++, value>>=1)
{
BDD tmp;
BDD v;
if (value & 0x1)
v = bdd_ithvar(variables[width-z-1]);
else
v = bdd_nithvar(variables[width-z-1]);
bdd_addref(result);
tmp = bdd_apply(result,v,bddop_and);
bdd_delref(result);
result = tmp;
}
return result;
}
/*=== NOT ==============================================================*/
/*
NAME {* bdd\_not *}
SECTION {* operator *}
SHORT {* negates a bdd *}
PROTO {* BDD bdd_not(BDD r) *}
DESCR {* Negates the BDD {\tt r} by exchanging
all references to the zero-terminal with references to the
one-terminal and vice versa. *}
RETURN {* The negated bdd. *}
*/
BDD bdd_not(BDD r)
{
BDD res;
firstReorder = 1;
CHECKa(r, bddfalse);
again:
if (setjmp(bddexception) == 0)
{
INITREF;
if (!firstReorder)
bdd_disable_reorder();
res = not_rec(r);
if (!firstReorder)
bdd_enable_reorder();
}
else
{
bdd_checkreorder();
if (firstReorder-- == 1)
goto again;
res = BDDZERO; /* avoid warning about res being uninitialized */
}
checkresize();
return res;
}
static BDD not_rec(BDD r)
{
BddCacheData *entry;
BDD res;
if (ISZERO(r))
return BDDONE;
if (ISONE(r))
return BDDZERO;
entry = BddCache_lookup(&applycache, NOTHASH(r));
if (entry->a == r && entry->c == bddop_not)
{
#ifdef CACHESTATS
bddcachestats.opHit++;
#endif
return entry->r.res;
}
#ifdef CACHESTATS
bddcachestats.opMiss++;
#endif
PUSHREF( not_rec(LOW(r)) );
PUSHREF( not_rec(HIGH(r)) );
res = bdd_makenode(LEVEL(r), READREF(2), READREF(1));
POPREF(2);
entry->a = r;
entry->c = bddop_not;
entry->r.res = res;
return res;
}
/*=== APPLY ============================================================*/
/*
NAME {* bdd\_apply *}
SECTION {* operator *}
SHORT {* basic bdd operations *}
PROTO {* BDD bdd_apply(BDD left, BDD right, int opr) *}
DESCR {* The {\tt bdd\_apply} function performs all of the basic
bdd operations with two operands, such as AND, OR etc.
The {\tt left} argument is the left bdd operand and {\tt right}
is the right operand. The {\tt opr} argument is the requested
operation and must be one of the following\\
\begin{tabular}{lllc}
{\bf Identifier} & {\bf Description} & {\bf Truth table}
& {\bf C++ opr.} \\
{\tt bddop\_and} & logical and ($A \wedge B$) & [0,0,0,1]
& \verb%&% \\
{\tt bddop\_xor} & logical xor ($A \oplus B$) & [0,1,1,0]
& \verb%^% \\
{\tt bddop\_or} & logical or ($A \vee B$) & [0,1,1,1]
& \verb%|% \\
{\tt bddop\_nand} & logical not-and & [1,1,1,0] \\
{\tt bddop\_nor} & logical not-or & [1,0,0,0] \\
{\tt bddop\_imp} & implication ($A \Rightarrow B$) & [1,1,0,1]
& \verb%>>% \\
{\tt bddop\_biimp} & bi-implication ($A \Leftrightarrow B$)& [1,0,0,1] \\
{\tt bddop\_diff} & set difference ($A \setminus B$) & [0,0,1,0]
& \verb%-% \\
{\tt bddop\_less} & less than ($A < B$) & [0,1,0,0]
& \verb%<% \\
{\tt bddop\_invimp} & reverse implication ($A \Leftarrow B$)& [1,0,1,1]
& \verb%<<% \\
\end{tabular}
*}
RETURN {* The result of the operation. *}
ALSO {* bdd\_ite *}
*/
BDD bdd_apply(BDD l, BDD r, int op)
{
BDD res;
firstReorder = 1;
CHECKa(l, bddfalse);
CHECKa(r, bddfalse);
if (op<0 || op>bddop_invimp)
{
bdd_error(BDD_OP);
return bddfalse;
}
again:
if (setjmp(bddexception) == 0)
{
INITREF;
applyop = op;
if (!firstReorder)
bdd_disable_reorder();
res = apply_rec(l, r);
if (!firstReorder)
bdd_enable_reorder();
}
else
{
bdd_checkreorder();
if (firstReorder-- == 1)
goto again;
res = BDDZERO; /* avoid warning about res being uninitialized */
}
checkresize();
return res;
}
static BDD apply_rec(BDD l, BDD r)
{
BddCacheData *entry;
BDD res;
switch (applyop)
{
case bddop_and:
if (l == r)
return l;
if (ISZERO(l) || ISZERO(r))
return 0;
if (ISONE(l))
return r;
if (ISONE(r))
return l;
break;
case bddop_or:
if (l == r)
return l;
if (ISONE(l) || ISONE(r))
return 1;
if (ISZERO(l))
return r;
if (ISZERO(r))
return l;
break;
case bddop_xor:
if (l == r)
return 0;
if (ISZERO(l))
return r;
if (ISZERO(r))
return l;
break;
case bddop_nand:
if (ISZERO(l) || ISZERO(r))
return 1;
break;
case bddop_nor:
if (ISONE(l) || ISONE(r))
return 0;
break;
case bddop_imp:
if (ISZERO(l))
return 1;
if (ISONE(l))
return r;
if (ISONE(r))
return 1;
break;
}
if (ISCONST(l) && ISCONST(r))
res = oprres[applyop][l<<1 | r];
else
{
entry = BddCache_lookup(&applycache, APPLYHASH(l,r,applyop));
if (entry->a == l && entry->b == r && entry->c == applyop)
{
#ifdef CACHESTATS
bddcachestats.opHit++;
#endif
return entry->r.res;
}
#ifdef CACHESTATS
bddcachestats.opMiss++;
#endif
if (LEVEL(l) == LEVEL(r))
{
PUSHREF( apply_rec(LOW(l), LOW(r)) );
PUSHREF( apply_rec(HIGH(l), HIGH(r)) );
res = bdd_makenode(LEVEL(l), READREF(2), READREF(1));
}
else
if (LEVEL(l) < LEVEL(r))
{
PUSHREF( apply_rec(LOW(l), r) );
PUSHREF( apply_rec(HIGH(l), r) );
res = bdd_makenode(LEVEL(l), READREF(2), READREF(1));
}
else
{
PUSHREF( apply_rec(l, LOW(r)) );
PUSHREF( apply_rec(l, HIGH(r)) );
res = bdd_makenode(LEVEL(r), READREF(2), READREF(1));
}
POPREF(2);
entry->a = l;
entry->b = r;
entry->c = applyop;
entry->r.res = res;
}
return res;
}
/*
NAME {* bdd\_and *}
SECTION {* operator *}
SHORT {* The logical 'and' of two BDDs *}
PROTO {* BDD bdd_and(BDD l, BDD r) *}
DESCR {* This a wrapper that calls {\tt bdd\_apply(l,r,bddop\_and)}. *}
RETURN {* The logical 'and' of {\tt l} and {\tt r}. *}
ALSO {* bdd\_apply, bdd\_or, bdd\_xor *}
*/
BDD bdd_and(BDD l, BDD r)
{
return bdd_apply(l,r,bddop_and);
}
/*
NAME {* bdd\_or *}
SECTION {* operator *}
SHORT {* The logical 'or' of two BDDs *}
PROTO {* BDD bdd_or(BDD l, BDD r) *}
DESCR {* This a wrapper that calls {\tt bdd\_apply(l,r,bddop\_or)}. *}
RETURN {* The logical 'or' of {\tt l} and {\tt r}. *}
ALSO {* bdd\_apply, bdd\_xor, bdd\_and *}
*/
BDD bdd_or(BDD l, BDD r)
{
return bdd_apply(l,r,bddop_or);
}
/*
NAME {* bdd\_xor *}
SECTION {* operator *}
SHORT {* The logical 'xor' of two BDDs *}
PROTO {* BDD bdd_xor(BDD l, BDD r) *}
DESCR {* This a wrapper that calls {\tt bdd\_apply(l,r,bddop\_xor)}. *}
RETURN {* The logical 'xor' of {\tt l} and {\tt r}. *}
ALSO {* bdd\_apply, bdd\_or, bdd\_and *}
*/
BDD bdd_xor(BDD l, BDD r)
{
return bdd_apply(l,r,bddop_xor);
}
/*
NAME {* bdd\_imp *}
SECTION {* operator *}
SHORT {* The logical 'implication' between two BDDs *}
PROTO {* BDD bdd_imp(BDD l, BDD r) *}
DESCR {* This a wrapper that calls {\tt bdd\_apply(l,r,bddop\_imp)}. *}
RETURN {* The logical 'implication' of {\tt l} and {\tt r} ($l \Rightarrow r$). *}
ALSO {* bdd\_apply, bdd\_biimp *}
*/
BDD bdd_imp(BDD l, BDD r)
{
return bdd_apply(l,r,bddop_imp);
}
/*
NAME {* bdd\_biimp *}
SECTION {* operator *}
SHORT {* The logical 'bi-implication' between two BDDs *}
PROTO {* BDD bdd_biimp(BDD l, BDD r) *}
DESCR {* This a wrapper that calls {\tt bdd\_apply(l,r,bddop\_biimp)}. *}
RETURN {* The logical 'bi-implication' of {\tt l} and {\tt r} ($l \Leftrightarrow r$). *}
ALSO {* bdd\_apply, bdd\_imp *}
*/
BDD bdd_biimp(BDD l, BDD r)
{
return bdd_apply(l,r,bddop_biimp);
}
/*=== ITE ==============================================================*/
/*
NAME {* bdd\_ite *}
SECTION {* operator *}
SHORT {* if-then-else operator *}
PROTO {* BDD bdd_ite(BDD f, BDD g, BDD h) *}
DESCR {* Calculates the BDD for the expression
$(f \conj g) \disj (\neg f \conj h)$ more efficiently than doing
the three operations separately. {\tt bdd\_ite} can also be used
for conjunction, disjunction and any other boolean operator, but
is not as efficient for the binary and unary operations. *}
RETURN {* The BDD for $(f \conj g) \disj (\neg f \conj h)$ *}
ALSO {* bdd\_apply *}
*/
BDD bdd_ite(BDD f, BDD g, BDD h)
{
BDD res;
firstReorder = 1;
CHECKa(f, bddfalse);
CHECKa(g, bddfalse);
CHECKa(h, bddfalse);
again:
if (setjmp(bddexception) == 0)
{
INITREF;
if (!firstReorder)
bdd_disable_reorder();
res = ite_rec(f,g,h);
if (!firstReorder)
bdd_enable_reorder();
}
else
{
bdd_checkreorder();
if (firstReorder-- == 1)
goto again;
res = BDDZERO; /* avoid warning about res being uninitialized */
}
checkresize();
return res;
}
static BDD ite_rec(BDD f, BDD g, BDD h)
{
BddCacheData *entry;
BDD res;
if (ISONE(f))
return g;
if (ISZERO(f))
return h;
if (g == h)
return g;
if (ISONE(g) && ISZERO(h))
return f;
if (ISZERO(g) && ISONE(h))
return not_rec(f);
entry = BddCache_lookup(&itecache, ITEHASH(f,g,h));
if (entry->a == f && entry->b == g && entry->c == h)
{
#ifdef CACHESTATS
bddcachestats.opHit++;
#endif
return entry->r.res;
}
#ifdef CACHESTATS
bddcachestats.opMiss++;
#endif
if (LEVEL(f) == LEVEL(g))
{
if (LEVEL(f) == LEVEL(h))
{
PUSHREF( ite_rec(LOW(f), LOW(g), LOW(h)) );
PUSHREF( ite_rec(HIGH(f), HIGH(g), HIGH(h)) );
res = bdd_makenode(LEVEL(f), READREF(2), READREF(1));
}
else
if (LEVEL(f) < LEVEL(h))
{
PUSHREF( ite_rec(LOW(f), LOW(g), h) );
PUSHREF( ite_rec(HIGH(f), HIGH(g), h) );
res = bdd_makenode(LEVEL(f), READREF(2), READREF(1));
}
else /* f > h */
{
PUSHREF( ite_rec(f, g, LOW(h)) );
PUSHREF( ite_rec(f, g, HIGH(h)) );
res = bdd_makenode(LEVEL(h), READREF(2), READREF(1));
}
}
else
if (LEVEL(f) < LEVEL(g))
{
if (LEVEL(f) == LEVEL(h))
{
PUSHREF( ite_rec(LOW(f), g, LOW(h)) );
PUSHREF( ite_rec(HIGH(f), g, HIGH(h)) );
res = bdd_makenode(LEVEL(f), READREF(2), READREF(1));
}
else
if (LEVEL(f) < LEVEL(h))
{
PUSHREF( ite_rec(LOW(f), g, h) );
PUSHREF( ite_rec(HIGH(f), g, h) );
res = bdd_makenode(LEVEL(f), READREF(2), READREF(1));
}
else /* f > h */
{
PUSHREF( ite_rec(f, g, LOW(h)) );
PUSHREF( ite_rec(f, g, HIGH(h)) );
res = bdd_makenode(LEVEL(h), READREF(2), READREF(1));
}
}
else /* f > g */
{
if (LEVEL(g) == LEVEL(h))
{
PUSHREF( ite_rec(f, LOW(g), LOW(h)) );
PUSHREF( ite_rec(f, HIGH(g), HIGH(h)) );
res = bdd_makenode(LEVEL(g), READREF(2), READREF(1));
}
else
if (LEVEL(g) < LEVEL(h))
{
PUSHREF( ite_rec(f, LOW(g), h) );
PUSHREF( ite_rec(f, HIGH(g), h) );
res = bdd_makenode(LEVEL(g), READREF(2), READREF(1));
}
else /* g > h */
{
PUSHREF( ite_rec(f, g, LOW(h)) );
PUSHREF( ite_rec(f, g, HIGH(h)) );
res = bdd_makenode(LEVEL(h), READREF(2), READREF(1));
}
}
POPREF(2);
entry->a = f;
entry->b = g;
entry->c = h;
entry->r.res = res;
return res;
}
/*=== RESTRICT =========================================================*/
/*
NAME {* bdd\_restrict *}
SECTION {* operator *}
SHORT {* restric a set of variables to constant values *}
PROTO {* BDD bdd_restrict(BDD r, BDD var) *}
DESCR {* This function restricts the variables in {\tt r} to constant
true or false. How this is done
depends on how the variables are included in the variable set
{\tt var}. If they
are included in their positive form then they are restricted to
true and vice versa. Unfortunately it is not possible to
insert variables in their negated form using {\tt bdd\_makeset},
so the variable set has to be build manually as a
conjunction of the variables. Example: Assume variable 1 should be
restricted to true and variable 3 to false.
\begin{verbatim}
bdd X = make_user_bdd();
bdd R1 = bdd_ithvar(1);
bdd R2 = bdd_nithvar(3);
bdd R = bdd_addref( bdd_apply(R1,R2, bddop_and) );
bdd RES = bdd_addref( bdd_restrict(X,R) );
\end{verbatim}
*}
RETURN {* The restricted bdd. *}
ALSO {* bdd\_makeset, bdd\_exist, bdd\_forall *}
*/
BDD bdd_restrict(BDD r, BDD var)
{
BDD res;
firstReorder = 1;
CHECKa(r,bddfalse);
CHECKa(var,bddfalse);
if (var < 2) /* Empty set */
return r;
again:
if (setjmp(bddexception) == 0)
{
if (varset2svartable(var) < 0)
return bddfalse;
INITREF;
miscid = (var << 3) | CACHEID_RESTRICT;
if (!firstReorder)
bdd_disable_reorder();
res = restrict_rec(r);
if (!firstReorder)
bdd_enable_reorder();
}
else
{
bdd_checkreorder();
if (firstReorder-- == 1)
goto again;
res = BDDZERO; /* avoid warning about res being uninitialized */
}
checkresize();
return res;
}
static int restrict_rec(int r)
{
BddCacheData *entry;
int res;
if (ISCONST(r) || LEVEL(r) > quantlast)
return r;
entry = BddCache_lookup(&misccache, RESTRHASH(r,miscid));
if (entry->a == r && entry->c == miscid)
{
#ifdef CACHESTATS
bddcachestats.opHit++;
#endif
return entry->r.res;
}
#ifdef CACHESTATS
bddcachestats.opMiss++;
#endif
if (INSVARSET(LEVEL(r)))
{
if (quantvarset[LEVEL(r)] > 0)
res = restrict_rec(HIGH(r));
else
res = restrict_rec(LOW(r));
}
else
{
PUSHREF( restrict_rec(LOW(r)) );
PUSHREF( restrict_rec(HIGH(r)) );
res = bdd_makenode(LEVEL(r), READREF(2), READREF(1));
POPREF(2);
}
entry->a = r;
entry->c = miscid;
entry->r.res = res;
return res;
}
/*=== GENERALIZED COFACTOR =============================================*/
/*
NAME {* bdd\_constrain *}
SECTION {* operator *}
SHORT {* generalized cofactor *}
PROTO {* BDD bdd_constrain(BDD f, BDD c) *}
DESCR {* Computes the generalized cofactor of {\tt f} with respect to
{\tt c}. *}
RETURN {* The constrained BDD *}
ALSO {* bdd\_restrict, bdd\_simplify *}
*/
BDD bdd_constrain(BDD f, BDD c)
{
BDD res;
firstReorder = 1;
CHECKa(f,bddfalse);
CHECKa(c,bddfalse);
again:
if (setjmp(bddexception) == 0)
{
INITREF;
miscid = CACHEID_CONSTRAIN;
if (!firstReorder)
bdd_disable_reorder();
res = constrain_rec(f, c);
if (!firstReorder)
bdd_enable_reorder();
}
else
{
bdd_checkreorder();
if (firstReorder-- == 1)
goto again;
res = BDDZERO; /* avoid warning about res being uninitialized */
}
checkresize();
return res;
}
static BDD constrain_rec(BDD f, BDD c)
{
BddCacheData *entry;
BDD res;
if (ISONE(c))
return f;
if (ISCONST(f))
return f;
if (c == f)
return BDDONE;
if (ISZERO(c))
return BDDZERO;
entry = BddCache_lookup(&misccache, CONSTRAINHASH(f,c));
if (entry->a == f && entry->b == c && entry->c == miscid)
{
#ifdef CACHESTATS
bddcachestats.opHit++;
#endif
return entry->r.res;
}
#ifdef CACHESTATS
bddcachestats.opMiss++;
#endif
if (LEVEL(f) == LEVEL(c))
{
if (ISZERO(LOW(c)))
res = constrain_rec(HIGH(f), HIGH(c));
else if (ISZERO(HIGH(c)))
res = constrain_rec(LOW(f), LOW(c));
else
{
PUSHREF( constrain_rec(LOW(f), LOW(c)) );
PUSHREF( constrain_rec(HIGH(f), HIGH(c)) );
res = bdd_makenode(LEVEL(f), READREF(2), READREF(1));
POPREF(2);
}
}
else
if (LEVEL(f) < LEVEL(c))
{
PUSHREF( constrain_rec(LOW(f), c) );
PUSHREF( constrain_rec(HIGH(f), c) );
res = bdd_makenode(LEVEL(f), READREF(2), READREF(1));
POPREF(2);
}
else
{
if (ISZERO(LOW(c)))
res = constrain_rec(f, HIGH(c));
else if (ISZERO(HIGH(c)))
res = constrain_rec(f, LOW(c));
else
{
PUSHREF( constrain_rec(f, LOW(c)) );
PUSHREF( constrain_rec(f, HIGH(c)) );
res = bdd_makenode(LEVEL(c), READREF(2), READREF(1));
POPREF(2);
}
}
entry->a = f;
entry->b = c;
entry->c = miscid;
entry->r.res = res;
return res;
}
/*=== REPLACE ==========================================================*/
/*
NAME {* bdd\_replace *}
SECTION {* operator *}
SHORT {* replaces variables with other variables *}
PROTO {* BDD bdd_replace(BDD r, bddPair *pair) *}
DESCR {* Replaces all variables in the BDD {\tt r} with the variables
defined by {\tt pair}. Each entry in {\tt pair} consists of a
old and a new variable. Whenever the old variable is found in
{\tt r} then a new node with the new variable is inserted instead.
*}
ALSO {* bdd\_newpair, bdd\_setpair, bdd\_setpairs *}
RETURN {* The result of the operation. *}
*/
BDD bdd_replace(BDD r, bddPair *pair)
{
BDD res;
firstReorder = 1;
CHECKa(r, bddfalse);
again:
if (setjmp(bddexception) == 0)
{
INITREF;
replacepair = pair->result;
replacelast = pair->last;
replaceid = (pair->id << 2) | CACHEID_REPLACE;
if (!firstReorder)
bdd_disable_reorder();
res = replace_rec(r);
if (!firstReorder)
bdd_enable_reorder();
}
else
{
bdd_checkreorder();
if (firstReorder-- == 1)
goto again;
res = BDDZERO; /* avoid warning about res being uninitialized */
}
checkresize();
return res;
}
static BDD replace_rec(BDD r)
{
BddCacheData *entry;
BDD res;
if (ISCONST(r) || LEVEL(r) > replacelast)
return r;
entry = BddCache_lookup(&replacecache, REPLACEHASH(r));
if (entry->a == r && entry->c == replaceid)
{
#ifdef CACHESTATS
bddcachestats.opHit++;
#endif
return entry->r.res;
}
#ifdef CACHESTATS
bddcachestats.opMiss++;
#endif
PUSHREF( replace_rec(LOW(r)) );
PUSHREF( replace_rec(HIGH(r)) );
res = bdd_correctify(LEVEL(replacepair[LEVEL(r)]), READREF(2), READREF(1));
POPREF(2);
entry->a = r;
entry->c = replaceid;
entry->r.res = res;
return res;
}
static BDD bdd_correctify(int level, BDD l, BDD r)
{
BDD res;
if (level < LEVEL(l) && level < LEVEL(r))
return bdd_makenode(level, l, r);
if (level == LEVEL(l) || level == LEVEL(r))
{
bdd_error(BDD_REPLACE);
return 0;
}
if (LEVEL(l) == LEVEL(r))
{
PUSHREF( bdd_correctify(level, LOW(l), LOW(r)) );
PUSHREF( bdd_correctify(level, HIGH(l), HIGH(r)) );
res = bdd_makenode(LEVEL(l), READREF(2), READREF(1));
}
else
if (LEVEL(l) < LEVEL(r))
{
PUSHREF( bdd_correctify(level, LOW(l), r) );
PUSHREF( bdd_correctify(level, HIGH(l), r) );
res = bdd_makenode(LEVEL(l), READREF(2), READREF(1));
}
else
{
PUSHREF( bdd_correctify(level, l, LOW(r)) );
PUSHREF( bdd_correctify(level, l, HIGH(r)) );
res = bdd_makenode(LEVEL(r), READREF(2), READREF(1));
}
POPREF(2);
return res; /* FIXME: cache ? */
}
/*=== COMPOSE ==========================================================*/
/*
NAME {* bdd\_compose *}
SECTION {* operator *}
SHORT {* functional composition *}
PROTO {* BDD bdd_compose(BDD f, BDD g, int var) *}
DESCR {* Substitutes the variable {\tt var} with the BDD {\tt g} in
the BDD {\tt f}: result $= f[g/var]$. *}
RETURN {* The composed BDD *}
ALSO {* bdd\_veccompose, bdd\_replace, bdd\_restrict *}
*/
BDD bdd_compose(BDD f, BDD g, int var)
{
BDD res;
firstReorder = 1;
CHECKa(f, bddfalse);
CHECKa(g, bddfalse);
if (var < 0 || var >= bddvarnum)
{
bdd_error(BDD_VAR);
return bddfalse;
}
again:
if (setjmp(bddexception) == 0)
{
INITREF;
composelevel = bddvar2level[var];
replaceid = (composelevel << 2) | CACHEID_COMPOSE;
if (!firstReorder)
bdd_disable_reorder();
res = compose_rec(f, g);
if (!firstReorder)
bdd_enable_reorder();
}
else
{
bdd_checkreorder();
if (firstReorder-- == 1)
goto again;
res = BDDZERO; /* avoid warning about res being uninitialized */
}
checkresize();
return res;
}
static BDD compose_rec(BDD f, BDD g)
{
BddCacheData *entry;
BDD res;
if (LEVEL(f) > composelevel)
return f;
entry = BddCache_lookup(&replacecache, COMPOSEHASH(f,g));
if (entry->a == f && entry->b == g && entry->c == replaceid)
{
#ifdef CACHESTATS
bddcachestats.opHit++;
#endif
return entry->r.res;
}
#ifdef CACHESTATS
bddcachestats.opMiss++;
#endif
if (LEVEL(f) < composelevel)
{
if (LEVEL(f) == LEVEL(g))
{
PUSHREF( compose_rec(LOW(f), LOW(g)) );
PUSHREF( compose_rec(HIGH(f), HIGH(g)) );
res = bdd_makenode(LEVEL(f), READREF(2), READREF(1));
}
else
if (LEVEL(f) < LEVEL(g))
{
PUSHREF( compose_rec(LOW(f), g) );
PUSHREF( compose_rec(HIGH(f), g) );
res = bdd_makenode(LEVEL(f), READREF(2), READREF(1));
}
else
{
PUSHREF( compose_rec(f, LOW(g)) );
PUSHREF( compose_rec(f, HIGH(g)) );
res = bdd_makenode(LEVEL(g), READREF(2), READREF(1));
}
POPREF(2);
}
else
/*if (LEVEL(f) == composelevel) changed 2-nov-98 */
{
res = ite_rec(g, HIGH(f), LOW(f));
}
entry->a = f;
entry->b = g;
entry->c = replaceid;
entry->r.res = res;
return res;
}
/*
NAME {* bdd\_veccompose *}
SECTION {* operator *}
SHORT {* simultaneous functional composition *}
PROTO {* BDD bdd_veccompose(BDD f, bddPair *pair) *}
DESCR {* Uses the pairs of variables and BDDs in {\tt pair} to make
the simultaneous substitution: $f[g_1/V_1, \ldots, g_n/V_n]$.
In this way one or more BDDs
may be substituted in one step. The BDDs in
{\tt pair} may depend on the variables they are substituting.
{\tt bdd\_compose} may be used instead of
{\tt bdd\_replace} but is not as efficient when $g_i$ is a
single variable, the same applies to {\tt bdd\_restrict}.
Note that simultaneous substitution is not necessarily the same
as repeated substitution. Example:
$(x_1 \disj x_2)[x_3/x_1,x_4/x_3] = (x_3 \disj x_2) \neq
((x_1 \disj x_2)[x_3/x_1])[x_4/x_3] = (x_4 \disj x_2)$. *}
RETURN {* The composed BDD *}
ALSO {* bdd\_compose, bdd\_replace, bdd\_restrict *}
*/
BDD bdd_veccompose(BDD f, bddPair *pair)
{
BDD res;
firstReorder = 1;
CHECKa(f, bddfalse);
again:
if (setjmp(bddexception) == 0)
{
INITREF;
replacepair = pair->result;
replaceid = (pair->id << 2) | CACHEID_VECCOMPOSE;
replacelast = pair->last;
if (!firstReorder)
bdd_disable_reorder();
res = veccompose_rec(f);
if (!firstReorder)
bdd_enable_reorder();
}
else
{
bdd_checkreorder();
if (firstReorder-- == 1)
goto again;
res = BDDZERO; /* avoid warning about res being uninitialized */
}
checkresize();
return res;
}
static BDD veccompose_rec(BDD f)
{
BddCacheData *entry;
register BDD res;
if (LEVEL(f) > replacelast)
return f;
entry = BddCache_lookup(&replacecache, VECCOMPOSEHASH(f));
if (entry->a == f && entry->c == replaceid)
{
#ifdef CACHESTATS
bddcachestats.opHit++;
#endif
return entry->r.res;
}
#ifdef CACHESTATS
bddcachestats.opMiss++;
#endif
PUSHREF( veccompose_rec(LOW(f)) );
PUSHREF( veccompose_rec(HIGH(f)) );
res = ite_rec(replacepair[LEVEL(f)], READREF(1), READREF(2));
POPREF(2);
entry->a = f;
entry->c = replaceid;
entry->r.res = res;
return res;
}
/*=== SIMPLIFY =========================================================*/
/*
NAME {* bdd\_simplify *}
SECTION {* operator *}
SHORT {* coudert and Madre's restrict function *}
PROTO {* BDD bdd_simplify(BDD f, BDD d) *}
DESCR {* Tries to simplify the BDD {\tt f} by restricting it to the
domain covered by {\tt d}. No checks are done to see if the
result is actually smaller than the input. This can be done
by the user with a call to {\tt bdd\_nodecount}. *}
ALSO {* bdd\_restrict *}
RETURN {* The simplified BDD *}
*/
BDD bdd_simplify(BDD f, BDD d)
{
BDD res;
firstReorder = 1;
CHECKa(f, bddfalse);
CHECKa(d, bddfalse);
again:
if (setjmp(bddexception) == 0)
{
INITREF;
applyop = bddop_or;
if (!firstReorder)
bdd_disable_reorder();
res = simplify_rec(f, d);
if (!firstReorder)
bdd_enable_reorder();
}
else
{
bdd_checkreorder();
if (firstReorder-- == 1)
goto again;
res = BDDZERO; /* avoid warning about res being uninitialized */
}
checkresize();
return res;
}
static BDD simplify_rec(BDD f, BDD d)
{
BddCacheData *entry;
BDD res;
if (ISONE(d) || ISCONST(f))
return f;
if (d == f)
return BDDONE;
if (ISZERO(d))
return BDDZERO;
entry = BddCache_lookup(&applycache, APPLYHASH(f,d,bddop_simplify));
if (entry->a == f && entry->b == d && entry->c == bddop_simplify)
{
#ifdef CACHESTATS
bddcachestats.opHit++;
#endif
return entry->r.res;
}
#ifdef CACHESTATS
bddcachestats.opMiss++;
#endif
if (LEVEL(f) == LEVEL(d))
{
if (ISZERO(LOW(d)))
res = simplify_rec(HIGH(f), HIGH(d));
else
if (ISZERO(HIGH(d)))
res = simplify_rec(LOW(f), LOW(d));
else
{
PUSHREF( simplify_rec(LOW(f), LOW(d)) );
PUSHREF( simplify_rec(HIGH(f), HIGH(d)) );
res = bdd_makenode(LEVEL(f), READREF(2), READREF(1));
POPREF(2);
}
}
else
if (LEVEL(f) < LEVEL(d))
{
PUSHREF( simplify_rec(LOW(f), d) );
PUSHREF( simplify_rec(HIGH(f), d) );
res = bdd_makenode(LEVEL(f), READREF(2), READREF(1));
POPREF(2);
}
else /* LEVEL(d) < LEVEL(f) */
{
PUSHREF( apply_rec(LOW(d), HIGH(d)) ); /* Exist quant */
res = simplify_rec(f, READREF(1));
POPREF(1);
}
entry->a = f;
entry->b = d;
entry->c = bddop_simplify;
entry->r.res = res;
return res;
}
/*=== QUANTIFICATION ===================================================*/
/*
NAME {* bdd\_exist *}
SECTION {* operator *}
SHORT {* existential quantification of variables *}
PROTO {* BDD bdd_exist(BDD r, BDD var) *}
DESCR {* Removes all occurences in {\tt r} of variables in the set
{\tt var} by existential quantification. *}
ALSO {* bdd\_forall, bdd\_unique, bdd\_makeset *}
RETURN {* The quantified BDD. *}
*/
BDD bdd_exist(BDD r, BDD var)
{
BDD res;
firstReorder = 1;
CHECKa(r, bddfalse);
CHECKa(var, bddfalse);
if (var < 2) /* Empty set */
return r;
again:
if (setjmp(bddexception) == 0)
{
if (varset2vartable(var) < 0)
return bddfalse;
INITREF;
quantid = (var << 3) | CACHEID_EXIST; /* FIXME: range */
applyop = bddop_or;
if (!firstReorder)
bdd_disable_reorder();
res = quant_rec(r);
if (!firstReorder)
bdd_enable_reorder();
}
else
{
bdd_checkreorder();
if (firstReorder-- == 1)
goto again;
res = BDDZERO; /* avoid warning about res being uninitialized */
}
checkresize();
return res;
}
/*
NAME {* bdd\_forall *}
SECTION {* operator *}
SHORT {* universal quantification of variables *}
PROTO {* BDD bdd_forall(BDD r, BDD var) *}
DESCR {* Removes all occurences in {\tt r} of variables in the set
{\tt var} by universal quantification. *}
ALSO {* bdd\_exist, bdd\_unique, bdd\_makeset *}
RETURN {* The quantified BDD. *}
*/
BDD bdd_forall(BDD r, BDD var)
{
BDD res;
firstReorder = 1;
CHECKa(r, bddfalse);
CHECKa(var, bddfalse);
if (var < 2) /* Empty set */
return r;
again:
if (setjmp(bddexception) == 0)
{
if (varset2vartable(var) < 0)
return bddfalse;
INITREF;
quantid = (var << 3) | CACHEID_FORALL;
applyop = bddop_and;
if (!firstReorder)
bdd_disable_reorder();
res = quant_rec(r);
if (!firstReorder)
bdd_enable_reorder();
}
else
{
bdd_checkreorder();
if (firstReorder-- == 1)
goto again;
res = BDDZERO; /* avoid warning about res being uninitialized */
}
checkresize();
return res;
}
/*
NAME {* bdd\_unique *}
SECTION {* operator *}
SHORT {* unique quantification of variables *}
PROTO {* BDD bdd_unique(BDD r, BDD var) *}
DESCR {* Removes all occurences in {\tt r} of variables in the set
{\tt var} by unique quantification. This type of quantification
uses a XOR operator instead of an OR operator as in the
existential quantification, and an AND operator as in the
universal quantification. *}
ALSO {* bdd\_exist, bdd\_forall, bdd\_makeset *}
RETURN {* The quantified BDD. *}
*/
BDD bdd_unique(BDD r, BDD var)
{
BDD res;
firstReorder = 1;
CHECKa(r, bddfalse);
CHECKa(var, bddfalse);
if (var < 2) /* Empty set */
return r;
again:
if (setjmp(bddexception) == 0)
{
if (varset2vartable(var) < 0)
return bddfalse;
INITREF;
quantid = (var << 3) | CACHEID_UNIQUE;
applyop = bddop_xor;
if (!firstReorder)
bdd_disable_reorder();
res = quant_rec(r);
if (!firstReorder)
bdd_enable_reorder();
}
else
{
bdd_checkreorder();
if (firstReorder-- == 1)
goto again;
res = BDDZERO; /* avoid warning about res being uninitialized */
}
checkresize();
return res;
}
static int quant_rec(int r)
{
BddCacheData *entry;
int res;
if (r < 2 || LEVEL(r) > quantlast)
return r;
entry = BddCache_lookup(&quantcache, QUANTHASH(r));
if (entry->a == r && entry->c == quantid)
{
#ifdef CACHESTATS
bddcachestats.opHit++;
#endif
return entry->r.res;
}
#ifdef CACHESTATS
bddcachestats.opMiss++;
#endif
PUSHREF( quant_rec(LOW(r)) );
PUSHREF( quant_rec(HIGH(r)) );
if (INVARSET(LEVEL(r)))
res = apply_rec(READREF(2), READREF(1));
else
res = bdd_makenode(LEVEL(r), READREF(2), READREF(1));
POPREF(2);
entry->a = r;
entry->c = quantid;
entry->r.res = res;
return res;
}
/*=== APPLY & QUANTIFY =================================================*/
/*
NAME {* bdd\_appex *}
SECTION {* operator *}
SHORT {* apply operation and existential quantification *}
PROTO {* BDD bdd_appex(BDD left, BDD right, int opr, BDD var) *}
DESCR {* Applies the binary operator {\tt opr} to the arguments
{\tt left} and {\tt right} and then performs an existential
quantification of the variables from the variable set
{\tt var}. This is done in a bottom up manner such that both the
apply and quantification is done on the lower nodes before
stepping up to the higher nodes. This makes the {\tt bdd\_appex}
function much more efficient than an apply operation followed
by a quantification. If the operator is a conjunction then this
is similar to the relational product of the two BDDs.
\index{relational product} *}
ALSO {* bdd\_appall, bdd\_appuni, bdd\_apply, bdd\_exist, bdd\_forall, bdd\_unique, bdd\_makeset *}
RETURN {* The result of the operation. *}
*/
BDD bdd_appex(BDD l, BDD r, int opr, BDD var)
{
BDD res;
firstReorder = 1;
CHECKa(l, bddfalse);
CHECKa(r, bddfalse);
CHECKa(var, bddfalse);
if (opr<0 || opr>bddop_invimp)
{
bdd_error(BDD_OP);
return bddfalse;
}
if (var < 2) /* Empty set */
return bdd_apply(l,r,opr);
again:
if (setjmp(bddexception) == 0)
{
if (varset2vartable(var) < 0)
return bddfalse;
INITREF;
applyop = bddop_or;
appexop = opr;
appexid = (var << 5) | (appexop << 1); /* FIXME: range! */
quantid = (appexid << 3) | CACHEID_APPEX;
if (!firstReorder)
bdd_disable_reorder();
res = appquant_rec(l, r);
if (!firstReorder)
bdd_enable_reorder();
}
else
{
bdd_checkreorder();
if (firstReorder-- == 1)
goto again;
res = BDDZERO; /* avoid warning about res being uninitialized */
}
checkresize();
return res;
}
/*
NAME {* bdd\_appall *}
SECTION {* operator *}
SHORT {* apply operation and universal quantification *}
PROTO {* BDD bdd_appall(BDD left, BDD right, int opr, BDD var) *}
DESCR {* Applies the binary operator {\tt opr} to the arguments
{\tt left} and {\tt right} and then performs an universal
quantification of the variables from the variable set
{\tt var}. This is done in a bottom up manner such that both the
apply and quantification is done on the lower nodes before
stepping up to the higher nodes. This makes the {\tt bdd\_appall}
function much more efficient than an apply operation followed
by a quantification. *}
ALSO {* bdd\_appex, bdd\_appuni, bdd\_apply, bdd\_exist, bdd\_forall, bdd\_unique, bdd\_makeset *}
RETURN {* The result of the operation. *}
*/
BDD bdd_appall(BDD l, BDD r, int opr, BDD var)
{
BDD res;
firstReorder = 1;
CHECKa(l, bddfalse);
CHECKa(r, bddfalse);
CHECKa(var, bddfalse);
if (opr<0 || opr>bddop_invimp)
{
bdd_error(BDD_OP);
return bddfalse;
}
if (var < 2) /* Empty set */
return bdd_apply(l,r,opr);
again:
if (setjmp(bddexception) == 0)
{
if (varset2vartable(var) < 0)
return bddfalse;
INITREF;
applyop = bddop_and;
appexop = opr;
appexid = (var << 5) | (appexop << 1) | 1; /* FIXME: range! */
quantid = (appexid << 3) | CACHEID_APPAL;
if (!firstReorder)
bdd_disable_reorder();
res = appquant_rec(l, r);
if (!firstReorder)
bdd_enable_reorder();
}
else
{
bdd_checkreorder();
if (firstReorder-- == 1)
goto again;
res = BDDZERO; /* avoid warning about res being uninitialized */
}
checkresize();
return res;
}
/*
NAME {* bdd\_appuni *}
SECTION {* operator *}
SHORT {* apply operation and unique quantification *}
PROTO {* BDD bdd_appuni(BDD left, BDD right, int opr, BDD var) *}
DESCR {* Applies the binary operator {\tt opr} to the arguments
{\tt left} and {\tt right} and then performs a unique
quantification of the variables from the variable set
{\tt var}. This is done in a bottom up manner such that both the
apply and quantification is done on the lower nodes before
stepping up to the higher nodes. This makes the {\tt bdd\_appuni}
function much more efficient than an apply operation followed
by a quantification. *}
ALSO {* bdd\_appex, bdd\_appall, bdd\_apply, bdd\_exist, bdd\_unique, bdd\_forall, bdd\_makeset *}
RETURN {* The result of the operation. *}
*/
BDD bdd_appuni(BDD l, BDD r, int opr, BDD var)
{
BDD res;
firstReorder = 1;
CHECKa(l, bddfalse);
CHECKa(r, bddfalse);
CHECKa(var, bddfalse);
if (opr<0 || opr>bddop_invimp)
{
bdd_error(BDD_OP);
return bddfalse;
}
if (var < 2) /* Empty set */
return bdd_apply(l,r,opr);
again:
if (setjmp(bddexception) == 0)
{
if (varset2vartable(var) < 0)
return bddfalse;
INITREF;
applyop = bddop_xor;
appexop = opr;
appexid = (var << 5) | (appexop << 1) | 1; /* FIXME: range! */
quantid = (appexid << 3) | CACHEID_APPUN;
if (!firstReorder)
bdd_disable_reorder();
res = appquant_rec(l, r);
if (!firstReorder)
bdd_enable_reorder();
}
else
{
bdd_checkreorder();
if (firstReorder-- == 1)
goto again;
res = BDDZERO; /* avoid warning about res being uninitialized */
}
checkresize();
return res;
}
static int appquant_rec(int l, int r)
{
BddCacheData *entry;
int res;
switch (appexop)
{
case bddop_and:
if (l == 0 || r == 0)
return 0;
if (l == r)
return quant_rec(l);
if (l == 1)
return quant_rec(r);
if (r == 1)
return quant_rec(l);
break;
case bddop_or:
if (l == 1 || r == 1)
return 1;
if (l == r)
return quant_rec(l);
if (l == 0)
return quant_rec(r);
if (r == 0)
return quant_rec(l);
break;
case bddop_xor:
if (l == r)
return 0;
if (l == 0)
return quant_rec(r);
if (r == 0)
return quant_rec(l);
break;
case bddop_nand:
if (l == 0 || r == 0)
return 1;
break;
case bddop_nor:
if (l == 1 || r == 1)
return 0;
break;
}
if (ISCONST(l) && ISCONST(r))
res = oprres[appexop][(l<<1) | r];
else
if (LEVEL(l) > quantlast && LEVEL(r) > quantlast)
{
int oldop = applyop;
applyop = appexop;
res = apply_rec(l,r);
applyop = oldop;
}
else
{
entry = BddCache_lookup(&appexcache, APPEXHASH(l,r,appexop));
if (entry->a == l && entry->b == r && entry->c == appexid)
{
#ifdef CACHESTATS
bddcachestats.opHit++;
#endif
return entry->r.res;
}
#ifdef CACHESTATS
bddcachestats.opMiss++;
#endif
if (LEVEL(l) == LEVEL(r))
{
PUSHREF( appquant_rec(LOW(l), LOW(r)) );
PUSHREF( appquant_rec(HIGH(l), HIGH(r)) );
if (INVARSET(LEVEL(l)))
res = apply_rec(READREF(2), READREF(1));
else
res = bdd_makenode(LEVEL(l), READREF(2), READREF(1));
}
else
if (LEVEL(l) < LEVEL(r))
{
PUSHREF( appquant_rec(LOW(l), r) );
PUSHREF( appquant_rec(HIGH(l), r) );
if (INVARSET(LEVEL(l)))
res = apply_rec(READREF(2), READREF(1));
else
res = bdd_makenode(LEVEL(l), READREF(2), READREF(1));
}
else
{
PUSHREF( appquant_rec(l, LOW(r)) );
PUSHREF( appquant_rec(l, HIGH(r)) );
if (INVARSET(LEVEL(r)))
res = apply_rec(READREF(2), READREF(1));
else
res = bdd_makenode(LEVEL(r), READREF(2), READREF(1));
}
POPREF(2);
entry->a = l;
entry->b = r;
entry->c = appexid;
entry->r.res = res;
}
return res;
}
/*************************************************************************
Informational functions
*************************************************************************/
/*=== SUPPORT ==========================================================*/
/*
NAME {* bdd\_support *}
SECTION {* info *}
SHORT {* returns the variable support of a BDD *}
PROTO {* BDD bdd_support(BDD r) *}
DESCR {* Finds all the variables that {\tt r} depends on. That is
the support of {\tt r}. *}
ALSO {* bdd\_makeset *}
RETURN {* A BDD variable set. *}
*/
BDD bdd_support(BDD r)
{
static int supportSize = 0;
int n;
int res=1;
CHECKa(r, bddfalse);
if (r < 2)
return bddfalse;
/* On-demand allocation of support set */
if (supportSize < bddvarnum)
{
if ((supportSet=(int*)malloc(bddvarnum*sizeof(int))) == NULL)
{
bdd_error(BDD_MEMORY);
return bddfalse;
}
memset(supportSet, 0, bddvarnum*sizeof(int));
supportSize = bddvarnum;
supportID = 0;
}
/* Update global variables used to speed up bdd_support()
* - instead of always memsetting support to zero, we use
* a change counter.
* - and instead of reading the whole array afterwards, we just
* look from 'min' to 'max' used BDD variables.
*/
if (supportID == 0x0FFFFFFF)
{
/* We probably don't get here -- but let's just be sure */
memset(supportSet, 0, bddvarnum*sizeof(int));
supportID = 0;
}
++supportID;
supportMin = LEVEL(r);
supportMax = supportMin;
support_rec(r, supportSet);
bdd_unmark(r);
bdd_disable_reorder();
for (n=supportMax ; n>=supportMin ; --n)
if (supportSet[n] == supportID)
{
register BDD tmp;
bdd_addref(res);
tmp = bdd_makenode(n, 0, res);
bdd_delref(res);
res = tmp;
}
bdd_enable_reorder();
return res;
}
static void support_rec(int r, int* support)
{
BddNode *node;
if (r < 2)
return;
node = &bddnodes[r];
if (LEVELp(node) & MARKON || LOWp(node) == -1)
return;
support[LEVELp(node)] = supportID;
if (LEVELp(node) > supportMax)
supportMax = LEVELp(node);
LEVELp(node) |= MARKON;
support_rec(LOWp(node), support);
support_rec(HIGHp(node), support);
}
/*=== ONE SATISFYING VARIABLE ASSIGNMENT ===============================*/
/*
NAME {* bdd\_satone *}
SECTION {* operator *}
SHORT {* finds one satisfying variable assignment *}
PROTO {* BDD bdd_satone(BDD r) *}
DESCR {* Finds a BDD with at most one variable at each level. This BDD
implies {\tt r} and is not false unless {\tt r} is
false. *}
ALSO {* bdd\_allsat bdd\_satoneset, bdd\_fullsatone, bdd\_satcount, bdd\_satcountln *}
RETURN {* The result of the operation. *}
*/
BDD bdd_satone(BDD r)
{
BDD res;
CHECKa(r, bddfalse);
if (r < 2)
return r;
bdd_disable_reorder();
INITREF;
res = satone_rec(r);
bdd_enable_reorder();
checkresize();
return res;
}
static BDD satone_rec(BDD r)
{
if (ISCONST(r))
return r;
if (ISZERO(LOW(r)))
{
BDD res = satone_rec(HIGH(r));
return PUSHREF( bdd_makenode(LEVEL(r), BDDZERO, res) );
}
else
{
BDD res = satone_rec(LOW(r));
return PUSHREF( bdd_makenode(LEVEL(r), res, BDDZERO) );
}
}
/*
NAME {* bdd\_satoneset *}
SECTION {* operator *}
SHORT {* finds one satisfying variable assignment *}
PROTO {* BDD bdd_satoneset(BDD r, BDD var, BDD pol) *}
DESCR {* Finds a minterm in {\tt r}. The {\tt var} argument is a
variable set that defines a set of variables that {\em must} be
mentioned in the result. The polarity of these variables in
result---in case they are undefined in {\tt r}---are defined
by the {\tt pol} parameter. If {\tt pol} is the false BDD then
the variables will be in negative form, and otherwise they will
be in positive form. *}
ALSO {* bdd\_allsat bdd\_satone, bdd\_fullsatone, bdd\_satcount, bdd\_satcountln *}
RETURN {* The result of the operation. *}
*/
BDD bdd_satoneset(BDD r, BDD var, BDD pol)
{
BDD res;
CHECKa(r, bddfalse);
if (ISZERO(r))
return r;
if (!ISCONST(pol))
{
bdd_error(BDD_ILLBDD);
return bddfalse;
}
bdd_disable_reorder();
INITREF;
satPolarity = pol;
res = satoneset_rec(r, var);
bdd_enable_reorder();
checkresize();
return res;
}
static BDD satoneset_rec(BDD r, BDD var)
{
if (ISCONST(r) && ISCONST(var))
return r;
if (LEVEL(r) < LEVEL(var))
{
if (ISZERO(LOW(r)))
{
BDD res = satoneset_rec(HIGH(r), var);
return PUSHREF( bdd_makenode(LEVEL(r), BDDZERO, res) );
}
else
{
BDD res = satoneset_rec(LOW(r), var);
return PUSHREF( bdd_makenode(LEVEL(r), res, BDDZERO) );
}
}
else if (LEVEL(var) < LEVEL(r))
{
BDD res = satoneset_rec(r, HIGH(var));
if (satPolarity == BDDONE)
return PUSHREF( bdd_makenode(LEVEL(var), BDDZERO, res) );
else
return PUSHREF( bdd_makenode(LEVEL(var), res, BDDZERO) );
}
else /* LEVEL(r) == LEVEL(var) */
{
if (ISZERO(LOW(r)))
{
BDD res = satoneset_rec(HIGH(r), HIGH(var));
return PUSHREF( bdd_makenode(LEVEL(r), BDDZERO, res) );
}
else
{
BDD res = satoneset_rec(LOW(r), HIGH(var));
return PUSHREF( bdd_makenode(LEVEL(r), res, BDDZERO) );
}
}
}
/*=== EXACTLY ONE SATISFYING VARIABLE ASSIGNMENT =======================*/
/*
NAME {* bdd\_fullsatone *}
SECTION {* operator *}
SHORT {* finds one satisfying variable assignment *}
PROTO {* BDD bdd_fullsatone(BDD r) *}
DESCR {* Finds a BDD with exactly one variable at all levels. This BDD
implies {\tt r} and is not false unless {\tt r} is
false. *}
ALSO {* bdd\_allsat bdd\_satone, bdd\_satoneset, bdd\_satcount, bdd\_satcountln *}
RETURN {* The result of the operation. *}
*/
BDD bdd_fullsatone(BDD r)
{
BDD res;
int v;
CHECKa(r, bddfalse);
if (r == 0)
return 0;
bdd_disable_reorder();
INITREF;
res = fullsatone_rec(r);
for (v=LEVEL(r)-1 ; v>=0 ; v--)
{
res = PUSHREF( bdd_makenode(v, res, 0) );
}
bdd_enable_reorder();
checkresize();
return res;
}
static int fullsatone_rec(int r)
{
if (r < 2)
return r;
if (LOW(r) != 0)
{
int res = fullsatone_rec(LOW(r));
int v;
for (v=LEVEL(LOW(r))-1 ; v>LEVEL(r) ; v--)
{
res = PUSHREF( bdd_makenode(v, res, 0) );
}
return PUSHREF( bdd_makenode(LEVEL(r), res, 0) );
}
else
{
int res = fullsatone_rec(HIGH(r));
int v;
for (v=LEVEL(HIGH(r))-1 ; v>LEVEL(r) ; v--)
{
res = PUSHREF( bdd_makenode(v, res, 0) );
}
return PUSHREF( bdd_makenode(LEVEL(r), 0, res) );
}
}
/*=== ALL SATISFYING VARIABLE ASSIGNMENTS ==============================*/
/*
NAME {* bdd\_allsat *}
SECTION {* operator *}
SHORT {* finds all satisfying variable assignments *}
PROTO {* BDD bdd_allsat(BDD r, bddallsathandler handler) *}
DESCR {* Iterates through all legal variable assignments (those
that make the BDD come true) for the bdd {\tt r} and
calls the callback handler {\tt handler} for each of them.
The array passed to {\tt handler} contains one entry for
each of the globally defined variables. Each entry is either
0 if the variable is false, 1 if it is true, and -1 if it
is a don't care.
The following is an example of a callback handler that
prints 'X' for don't cares, '0' for zero, and '1' for one:
\begin{verbatim}
void allsatPrintHandler(char* varset, int size)
{
for (int v=0; v<size ; ++v)
{
cout << (varset[v] < 0 ? 'X' : (char)('0' + varset[v]));
}
cout << endl;
}
\end{verbatim}
\noindent
The handler can be used like this:
{\tt bdd\_allsat(r, allsatPrintHandler); } *}
ALSO {* bdd\_satone bdd\_satoneset, bdd\_fullsatone, bdd\_satcount, bdd\_satcountln *}
*/
void bdd_allsat(BDD r, bddallsathandler handler)
{
int v;
CHECKn(r);
if ((allsatProfile=(char*)malloc(bddvarnum)) == NULL)
{
bdd_error(BDD_MEMORY);
return;
}
for (v=LEVEL(r)-1 ; v>=0 ; --v)
allsatProfile[bddlevel2var[v]] = -1;
allsatHandler = handler;
INITREF;
allsat_rec(r);
free(allsatProfile);
}
static void allsat_rec(BDD r)
{
if (ISONE(r))
{
allsatHandler(allsatProfile, bddvarnum);
return;
}
if (ISZERO(r))
return;
if (!ISZERO(LOW(r)))
{
int v;
allsatProfile[bddlevel2var[LEVEL(r)]] = 0;
for (v=LEVEL(LOW(r))-1 ; v>LEVEL(r) ; --v)
{
allsatProfile[bddlevel2var[v]] = -1;
}
allsat_rec(LOW(r));
}
if (!ISZERO(HIGH(r)))
{
int v;
allsatProfile[bddlevel2var[LEVEL(r)]] = 1;
for (v=LEVEL(HIGH(r))-1 ; v>LEVEL(r) ; --v)
{
allsatProfile[bddlevel2var[v]] = -1;
}
allsat_rec(HIGH(r));
}
}
/*=== COUNT NUMBER OF SATISFYING ASSIGNMENT ============================*/
/*
NAME {* bdd\_satcount *}
EXTRA {* bdd\_setcountset *}
SECTION {* info *}
SHORT {* calculates the number of satisfying variable assignments *}
PROTO {* double bdd_satcount(BDD r)
double bdd_satcountset(BDD r, BDD varset) *}
DESCR {* Calculates how many possible variable assignments there exists
such that {\tt r} is satisfied (true). All defined
variables are considered in the first version. In the
second version, only the variables in the variable
set {\tt varset} are considered. This makes the function a
{\em lot} slower. *}
ALSO {* bdd\_satone, bdd\_fullsatone, bdd\_satcountln *}
RETURN {* The number of possible assignments. *}
*/
double bdd_satcount(BDD r)
{
double size=1;
CHECKa(r, 0.0);
miscid = CACHEID_SATCOU;
size = pow(2.0, (double)LEVEL(r));
return size * satcount_rec(r);
}
double bdd_satcountset(BDD r, BDD varset)
{
double unused = bddvarnum;
BDD n;
if (ISCONST(varset) || ISZERO(r)) /* empty set */
return 0.0;
for (n=varset ; !ISCONST(n) ; n=HIGH(n))
unused--;
unused = bdd_satcount(r) / pow(2.0,unused);
return unused >= 1.0 ? unused : 1.0;
}
static double satcount_rec(int root)
{
BddCacheData *entry;
BddNode *node;
double size, s;
if (root < 2)
return root;
entry = BddCache_lookup(&misccache, SATCOUHASH(root));
if (entry->a == root && entry->c == miscid)
return entry->r.dres;
node = &bddnodes[root];
size = 0;
s = 1;
s *= pow(2.0, (float)(LEVEL(LOWp(node)) - LEVELp(node) - 1));
size += s * satcount_rec(LOWp(node));
s = 1;
s *= pow(2.0, (float)(LEVEL(HIGHp(node)) - LEVELp(node) - 1));
size += s * satcount_rec(HIGHp(node));
entry->a = root;
entry->c = miscid;
entry->r.dres = size;
return size;
}
/*
NAME {* bdd\_satcountln *}
EXTRA {* bdd\_setcountlnset *}
SECTION {* info *}
SHORT {* calculates the log. number of satisfying variable assignments *}
PROTO {* double bdd_satcountln(BDD r)
double bdd_satcountlnset(BDD r, BDD varset)*}
DESCR {* Calculates how many possible variable assignments there
exists such that {\tt r} is satisfied (true) and returns
the logarithm of this. The result is calculated in such a
manner that it is practically impossible to get an
overflow, which is very possible for {\tt bdd\_satcount} if
the number of defined variables is too large. All defined
variables are considered in the first version. In the
second version, only the variables in the variable
set {\tt varset} are considered. This makes the function
a {\em lot} slower! *}
ALSO {* bdd\_satone, bdd\_fullsatone, bdd\_satcount *}
RETURN {* The logarithm of the number of possible assignments. *} */
double bdd_satcountln(BDD r)
{
double size;
CHECKa(r, 0.0);
miscid = CACHEID_SATCOULN;
size = satcountln_rec(r);
if (size >= 0.0)
size += LEVEL(r);
return size;
}
double bdd_satcountlnset(BDD r, BDD varset)
{
double unused = bddvarnum;
BDD n;
if (ISCONST(varset)) /* empty set */
return 0.0;
for (n=varset ; !ISCONST(n) ; n=HIGH(n))
unused--;
unused = bdd_satcountln(r) - unused;
return unused >= 0.0 ? unused : 0.0;
}
static double satcountln_rec(int root)
{
BddCacheData *entry;
BddNode *node;
double size, s1,s2;
if (root == 0)
return -1.0;
if (root == 1)
return 0.0;
entry = BddCache_lookup(&misccache, SATCOUHASH(root));
if (entry->a == root && entry->c == miscid)
return entry->r.dres;
node = &bddnodes[root];
s1 = satcountln_rec(LOWp(node));
if (s1 >= 0.0)
s1 += LEVEL(LOWp(node)) - LEVELp(node) - 1;
s2 = satcountln_rec(HIGHp(node));
if (s2 >= 0.0)
s2 += LEVEL(HIGHp(node)) - LEVELp(node) - 1;
if (s1 < 0.0)
size = s2;
else if (s2 < 0.0)
size = s1;
else if (s1 < s2)
size = s2 + log1p(pow(2.0,s1-s2)) / M_LN2;
else
size = s1 + log1p(pow(2.0,s2-s1)) / M_LN2;
entry->a = root;
entry->c = miscid;
entry->r.dres = size;
return size;
}
/*=== COUNT NUMBER OF ALLOCATED NODES ==================================*/
/*
NAME {* bdd\_nodecount *}
SECTION {* info *}
SHORT {* counts the number of nodes used for a BDD *}
PROTO {* int bdd_nodecount(BDD r) *}
DESCR {* Traverses the BDD and counts all distinct nodes that are used
for the BDD. *}
RETURN {* The number of nodes. *}
ALSO {* bdd\_pathcount, bdd\_satcount, bdd\_anodecount *}
*/
int bdd_nodecount(BDD r)
{
int num=0;
CHECK(r);
bdd_markcount(r, &num);
bdd_unmark(r);
return num;
}
/*
NAME {* bdd\_anodecount *}
SECTION {* info *}
SHORT {* counts the number of shared nodes in an array of BDDs *}
PROTO {* int bdd_anodecount(BDD *r, int num) *}
DESCR {* Traverses all of the BDDs in {\tt r} and counts all distinct nodes
that are used in the BDDs--if a node is used in more than one
BDD then it only counts once. The {\tt num} parameter holds the
size of the array. *}
RETURN {* The number of nodes *}
ALSO {* bdd\_nodecount *}
*/
int bdd_anodecount(BDD *r, int num)
{
int n;
int cou=0;
for (n=0 ; n<num ; n++)
bdd_markcount(r[n], &cou);
for (n=0 ; n<num ; n++)
bdd_unmark(r[n]);
return cou;
}
/*=== NODE PROFILE =====================================================*/
/*
NAME {* bdd\_varprofile *}
SECTION {* info *}
SHORT {* returns a variable profile *}
PROTO {* int *bdd_varprofile(BDD r) *}
DESCR {* Counts the number of times each variable occurs in the
bdd {\tt r}. The result is stored and returned in an integer array
where the i'th position stores the number of times the i'th
variable occured in the BDD. It is the users responsibility to
free the array again using a call to {\tt free}. *}
RETURN {* A pointer to an integer array with the profile or NULL if an
error occured. *}
*/
int *bdd_varprofile(BDD r)
{
CHECKa(r, NULL);
if ((varprofile=(int*)malloc(sizeof(int)*bddvarnum)) == NULL)
{
bdd_error(BDD_MEMORY);
return NULL;
}
memset(varprofile, 0, sizeof(int)*bddvarnum);
varprofile_rec(r);
bdd_unmark(r);
return varprofile;
}
static void varprofile_rec(int r)
{
BddNode *node;
if (r < 2)
return;
node = &bddnodes[r];
if (LEVELp(node) & MARKON)
return;
varprofile[bddlevel2var[LEVELp(node)]]++;
LEVELp(node) |= MARKON;
varprofile_rec(LOWp(node));
varprofile_rec(HIGHp(node));
}
/*=== COUNT NUMBER OF PATHS ============================================*/
/*
NAME {* bdd\_pathcount *}
SECTION {* info *}
SHORT {* count the number of paths leading to the true terminal *}
PROTO {* double bdd_pathcount(BDD r) *}
DESCR {* Counts the number of paths from the root node {\tt r}
leading to the terminal true node. *}
RETURN {* The number of paths *}
ALSO {* bdd\_nodecount, bdd\_satcount *}
*/
double bdd_pathcount(BDD r)
{
CHECKa(r, 0.0);
miscid = CACHEID_PATHCOU;
return bdd_pathcount_rec(r);
}
static double bdd_pathcount_rec(BDD r)
{
BddCacheData *entry;
double size;
if (ISZERO(r))
return 0.0;
if (ISONE(r))
return 1.0;
entry = BddCache_lookup(&misccache, PATHCOUHASH(r));
if (entry->a == r && entry->c == miscid)
return entry->r.dres;
size = bdd_pathcount_rec(LOW(r)) + bdd_pathcount_rec(HIGH(r));
entry->a = r;
entry->c = miscid;
entry->r.dres = size;
return size;
}
/*************************************************************************
Other internal functions
*************************************************************************/
static int varset2vartable(BDD r)
{
BDD n;
if (r < 2)
return bdd_error(BDD_VARSET);
quantvarsetID++;
if (quantvarsetID == INT_MAX)
{
memset(quantvarset, 0, sizeof(int)*bddvarnum);
quantvarsetID = 1;
}
for (n=r ; n > 1 ; n=HIGH(n))
{
quantvarset[LEVEL(n)] = quantvarsetID;
quantlast = LEVEL(n);
}
return 0;
}
static int varset2svartable(BDD r)
{
BDD n;
if (r < 2)
return bdd_error(BDD_VARSET);
quantvarsetID++;
if (quantvarsetID == INT_MAX/2)
{
memset(quantvarset, 0, sizeof(int)*bddvarnum);
quantvarsetID = 1;
}
for (n=r ; !ISCONST(n) ; )
{
if (ISZERO(LOW(n)))
{
quantvarset[LEVEL(n)] = quantvarsetID;
n = HIGH(n);
}
else
{
quantvarset[LEVEL(n)] = -quantvarsetID;
n = LOW(n);
}
quantlast = LEVEL(n);
}
return 0;
}
/* EOF */