// BDD.java, created Jan 29, 2003 9:50:57 PM by jwhaley
// Copyright (C) 2003 John Whaley
// Licensed under the terms of the GNU LGPL; see COPYING for details.
package net.sf.javabdd;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.io.PrintStream;
import java.math.BigInteger;
/**
* <p>Binary Decision Diagrams (BDDs) are used for efficient computation of many
* common problems. This is done by giving a compact representation and a set of
* efficient operations on boolean functions f: {0,1}^n --> {0,1}.</p>
*
* <p>Use an implementation of BDDFactory to create BDD objects.</p>
*
* <p>Some methods, namely <tt>exist()</tt>, <tt>forall()</tt>, <tt>unique()</tt>,
* <tt>relprod()</tt>, <tt>applyAll()</tt>, <tt>applyEx()</tt>, <tt>applyUni()</tt>,
* and <tt>satCount()</tt> take a 'set of variables' argument that is also of type BDD.
* Those BDDs must be a boolean function that represents the all-true minterm
* of the BDD variables of interest. They only serve to identify the set of
* variables of interest, however. For example, for a given BDDDomain, a BDD var set
* representing all BDD variables of that domain can be obtained
* by calling <tt>BDDDomain.set()</tt>.</p>
*
* @see net.sf.javabdd.BDDFactory
* @see net.sf.javabdd.BDDDomain#set()
*
* @author John Whaley
* @version $Id: BDD.java,v 1.5 2005/01/26 23:46:17 joewhaley Exp $
*/
public abstract class BDD {
/**
* <p>Returns the factory that created this BDD.</p>
*
* @return factory that created this BDD
*/
public abstract BDDFactory getFactory();
/**
* <p>Returns true if this BDD is the zero (false) BDD.</p>
*
* @return true if this BDD is the zero (false) BDD
*/
public abstract boolean isZero();
/**
* <p>Returns true if this BDD is the one (true) BDD.</p>
*
* @return true if this BDD is the one (true) BDD
*/
public abstract boolean isOne();
/**
* <p>Gets the variable labeling the BDD.</p>
*
* <p>Compare to bdd_var.</p>
*
* @return the index of the variable labeling the BDD
*/
public abstract int var();
/**
* <p>Gets the level of this BDD.</p>
*
* <p>Compare to LEVEL() macro.</p>
*
* @return the level of this BDD
*/
public int level() {
return getFactory().var2Level(var());
}
/**
* <p>Gets the true branch of this BDD.</p>
*
* <p>Compare to bdd_high.</p>
*
* @return true branch of this BDD
*/
public abstract BDD high();
/**
* <p>Gets the false branch of this BDD.</p>
*
* <p>Compare to bdd_low.</p>
*
* @return false branch of this BDD
*/
public abstract BDD low();
/**
* <p>Identity function. Returns a copy of this BDD. Use as the argument to
* the "xxxWith" style operators when you do not want to have the argument
* consumed.</p>
*
* <p>Compare to bdd_addref.</p>
*
* @return copy of this BDD
*/
public abstract BDD id();
/**
* <p>Negates this BDD by exchanging all references to the zero-terminal with
* references to the one-terminal and vice-versa.</p>
*
* <p>Compare to bdd_not.</p>
*
* @return the negated BDD
*/
public abstract BDD not();
/**
* <p>Returns the logical 'and' of two BDDs. This is a shortcut for calling
* "apply" with the "and" operator.</p>
*
* <p>Compare to bdd_and.</p>
*
* @param that BDD to 'and' with
* @return the logical 'and' of two BDDs
*/
public BDD and(BDD that) {
return this.apply(that, BDDFactory.and);
}
/**
* <p>Makes this BDD be the logical 'and' of two BDDs. The "that" BDD is
* consumed, and can no longer be used. This is a shortcut for calling
* "applyWith" with the "and" operator.</p>
*
* <p>Compare to bdd_and and bdd_delref.</p>
*
* @param that the BDD to 'and' with
*/
public BDD andWith(BDD that) {
return this.applyWith(that, BDDFactory.and);
}
/**
* <p>Returns the logical 'or' of two BDDs. This is a shortcut for calling
* "apply" with the "or" operator.</p>
*
* <p>Compare to bdd_or.</p>
*
* @param that the BDD to 'or' with
* @return the logical 'or' of two BDDs
*/
public BDD or(BDD that) {
return this.apply(that, BDDFactory.or);
}
/**
* <p>Makes this BDD be the logical 'or' of two BDDs. The "that" BDD is
* consumed, and can no longer be used. This is a shortcut for calling
* "applyWith" with the "or" operator.</p>
*
* <p>Compare to bdd_or and bdd_delref.</p>
*
* @param that the BDD to 'or' with
*/
public BDD orWith(BDD that) {
return this.applyWith(that, BDDFactory.or);
}
/**
* <p>Returns the logical 'xor' of two BDDs. This is a shortcut for calling
* "apply" with the "xor" operator.</p>
*
* <p>Compare to bdd_xor.</p>
*
* @param that the BDD to 'xor' with
* @return the logical 'xor' of two BDDs
*/
public BDD xor(BDD that) {
return this.apply(that, BDDFactory.xor);
}
/**
* <p>Makes this BDD be the logical 'xor' of two BDDs. The "that" BDD is
* consumed, and can no longer be used. This is a shortcut for calling
* "applyWith" with the "xor" operator.</p>
*
* <p>Compare to bdd_xor and bdd_delref.</p>
*
* @param that the BDD to 'xor' with
*/
public BDD xorWith(BDD that) {
return this.applyWith(that, BDDFactory.xor);
}
/**
* <p>Returns the logical 'implication' of two BDDs. This is a shortcut for
* calling "apply" with the "imp" operator.</p>
*
* <p>Compare to bdd_imp.</p>
*
* @param that the BDD to 'implication' with
* @return the logical 'implication' of two BDDs
*/
public BDD imp(BDD that) {
return this.apply(that, BDDFactory.imp);
}
/**
* <p>Makes this BDD be the logical 'implication' of two BDDs. The "that" BDD
* is consumed, and can no longer be used. This is a shortcut for calling
* "applyWith" with the "imp" operator.</p>
*
* <p>Compare to bdd_imp and bdd_delref.</p>
*
* @param that the BDD to 'implication' with
*/
public BDD impWith(BDD that) {
return this.applyWith(that, BDDFactory.imp);
}
/**
* <p>Returns the logical 'bi-implication' of two BDDs. This is a shortcut for
* calling "apply" with the "biimp" operator.</p>
*
* <p>Compare to bdd_biimp.</p>
*
* @param that the BDD to 'bi-implication' with
* @return the logical 'bi-implication' of two BDDs
*/
public BDD biimp(BDD that) {
return this.apply(that, BDDFactory.biimp);
}
/**
* <p>Makes this BDD be the logical 'bi-implication' of two BDDs. The "that"
* BDD is consumed, and can no longer be used. This is a shortcut for
* calling "applyWith" with the "biimp" operator.</p>
*
* <p>Compare to bdd_biimp and bdd_delref.</p>
*
* @param that the BDD to 'bi-implication' with
*/
public BDD biimpWith(BDD that) {
return this.applyWith(that, BDDFactory.biimp);
}
/**
* <p>if-then-else operator.</p>
*
* <p>Compare to bdd_ite.</p>
*
* @param thenBDD the 'then' BDD
* @param elseBDD the 'else' BDD
* @return the result of the if-then-else operator on the three BDDs
*/
public abstract BDD ite(BDD thenBDD, BDD elseBDD);
/**
* <p>Relational product. Calculates the relational product of the two BDDs as
* this AND that with the variables in var quantified out afterwards.
* Identical to applyEx(that, and, var).</p>
*
* <p>Compare to bdd_relprod.</p>
*
* @param that the BDD to 'and' with
* @param var the BDD to existentially quantify with
* @return the result of the relational product
* @see net.sf.javabdd.BDDDomain#set()
*/
public abstract BDD relprod(BDD that, BDD var);
/**
* <p>Functional composition. Substitutes the variable var with the BDD that
* in this BDD: result = f[g/var].</p>
*
* <p>Compare to bdd_compose.</p>
*
* @param g the function to use to replace
* @param var the variable number to replace
* @return the result of the functional composition
*/
public abstract BDD compose(BDD g, int var);
/**
* <p>Simultaneous functional composition. Uses the pairs of variables and
* BDDs in pair to make the simultaneous substitution: f [g1/V1, ... gn/Vn].
* In this way one or more BDDs may be substituted in one step. The BDDs in
* pair may depend on the variables they are substituting. BDD.compose()
* may be used instead of BDD.replace() but is not as efficient when gi is a
* single variable, the same applies to BDD.restrict(). Note that
* simultaneous substitution is not necessarily the same as repeated
* substitution.</p>
*
* <p>Compare to bdd_veccompose.</p>
*
* @param pair the pairing of variables to functions
* @return BDD the result of the simultaneous functional composition
*/
public abstract BDD veccompose(BDDPairing pair);
/**
* <p>Generalized cofactor. Computes the generalized cofactor of this BDD with
* respect to the given BDD.</p>
*
* <p>Compare to bdd_constrain.</p>
*
* @param that the BDD with which to compute the generalized cofactor
* @return the result of the generalized cofactor
*/
public abstract BDD constrain(BDD that);
/**
* <p>Existential quantification of variables. Removes all occurrences of this
* BDD in variables in the set var by existential quantification.</p>
*
* <p>Compare to bdd_exist.</p>
*
* @param var BDD containing the variables to be existentially quantified
* @return the result of the existential quantification
* @see net.sf.javabdd.BDDDomain#set()
*/
public abstract BDD exist(BDD var);
/**
* <p>Universal quantification of variables. Removes all occurrences of this
* BDD in variables in the set var by universal quantification.</p>
*
* <p>Compare to bdd_forall.</p>
*
* @param var BDD containing the variables to be universally quantified
* @return the result of the universal quantification
* @see net.sf.javabdd.BDDDomain#set()
*/
public abstract BDD forAll(BDD var);
/**
* <p>Unique quantification of variables. This type of quantification uses a
* XOR operator instead of an OR operator as in the existential
* quantification.</p>
*
* <p>Compare to bdd_unique.</p>
*
* @param var BDD containing the variables to be uniquely quantified
* @return the result of the unique quantification
* @see net.sf.javabdd.BDDDomain#set()
*/
public abstract BDD unique(BDD var);
/**
* <p>Restrict a set of variables to constant values. Restricts the variables
* in this BDD to constant true if they are included in their positive form
* in var, and constant false if they are included in their negative form.</p>
*
* <p><i>Note that this is quite different than Coudert and Madre's restrict
* function.</i></p>
*
* <p>Compare to bdd_restrict.</p>
*
* @param var BDD containing the variables to be restricted
* @return the result of the restrict operation
* @see net.sf.javabdd.BDD#simplify(BDD)
*/
public abstract BDD restrict(BDD var);
/**
* <p>Mutates this BDD to restrict a set of variables to constant values.
* Restricts the variables in this BDD to constant true if they are included
* in their positive form in var, and constant false if they are included in
* their negative form. The "that" BDD is consumed, and can no longer be used.</p>
*
* <p><i>Note that this is quite different than Coudert and Madre's restrict
* function.</i></p>
*
* <p>Compare to bdd_restrict and bdd_delref.</p>
*
* @param var BDD containing the variables to be restricted
* @see net.sf.javabdd.BDDDomain#set()
*/
public abstract BDD restrictWith(BDD var);
/**
* <p>Coudert and Madre's restrict function. Tries to simplify the BDD f by
* restricting it to the domain covered by 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 nodeCount().</p>
*
* <p>Compare to bdd_simplify.</p>
*
* @param d BDD containing the variables in the domain
* @return the result of the simplify operation
*/
public abstract BDD simplify(BDD d);
/**
* <p>Returns the variable support of this BDD. The support is all the
* variables that this BDD depends on.</p>
*
* <p>Compare to bdd_support.</p>
*
* @return the variable support of this BDD
*/
public abstract BDD support();
/**
* <p>Returns the result of applying the binary operator <tt>opr</tt> to the
* two BDDs.</p>
*
* <p>Compare to bdd_apply.</p>
*
* @param that the BDD to apply the operator on
* @param opr the operator to apply
* @return the result of applying the operator
*/
public abstract BDD apply(BDD that, BDDFactory.BDDOp opr);
/**
* <p>Makes this BDD be the result of the binary operator <tt>opr</tt> of two
* BDDs. The "that" BDD is consumed, and can no longer be used. Attempting
* to use the passed in BDD again will result in an exception being thrown.</p>
*
* <p>Compare to bdd_apply and bdd_delref.</p>
*
* @param that the BDD to apply the operator on
* @param opr the operator to apply
*/
public abstract BDD applyWith(BDD that, BDDFactory.BDDOp opr);
/**
* <p>Applies the binary operator <tt>opr</tt> to two BDDs and then performs a
* universal quantification of the variables from the variable set
* <tt>var</tt>.</p>
*
* <p>Compare to bdd_appall.</p>
*
* @param that the BDD to apply the operator on
* @param opr the operator to apply
* @param var BDD containing the variables to quantify
* @return the result
* @see net.sf.javabdd.BDDDomain#set()
*/
public abstract BDD applyAll(BDD that, BDDFactory.BDDOp opr, BDD var);
/**
* <p>Applies the binary operator <tt>opr</tt> to two BDDs and then performs
* an existential quantification of the variables from the variable set
* <tt>var</tt>.</p>
*
* <p>Compare to bdd_appex.</p>
*
* @param that the BDD to apply the operator on
* @param opr the operator to apply
* @param var BDD containing the variables to quantify
* @return the result
* @see net.sf.javabdd.BDDDomain#set()
*/
public abstract BDD applyEx(BDD that, BDDFactory.BDDOp opr, BDD var);
/**
* <p>Applies the binary operator <tt>opr</tt> to two BDDs and then performs
* a unique quantification of the variables from the variable set
* <tt>var</tt>.</p>
*
* <p>Compare to bdd_appuni.</p>
*
* @param that the BDD to apply the operator on
* @param opr the operator to apply
* @param var BDD containing the variables to quantify
* @return the result
* @see net.sf.javabdd.BDDDomain#set()
*/
public abstract BDD applyUni(BDD that, BDDFactory.BDDOp opr, BDD var);
/**
* <p>Finds one satisfying variable assignment. Finds a BDD with at most one
* variable at each level. The new BDD implies this BDD and is not false
* unless this BDD is false.</p>
*
* <p>Compare to bdd_satone.</p>
*
* @return one satisfying variable assignment
*/
public abstract BDD satOne();
/**
* <p>Finds one satisfying variable assignment. Finds a BDD with exactly one
* variable at all levels. The new BDD implies this BDD and is not false
* unless this BDD is false.</p>
*
* <p>Compare to bdd_fullsatone.</p>
*
* @return one satisfying variable assignment
*/
public abstract BDD fullSatOne();
/**
* <p>Finds one satisfying variable assignment. Finds a minterm in this BDD.
* The <tt>var</tt> argument is a set of variables that must be mentioned in
* the result. The polarity of these variables in the result - in case they
* are undefined in this BDD - are defined by the <tt>pol</tt> parameter.
* If <tt>pol</tt> is false, then all variables will be in negative form.
* Otherwise they will be in positive form.</p>
*
* <p>Compare to bdd_satoneset.</p>
*
* @param var BDD containing the set of variables that must be mentioned in the result
* @param pol the polarity of the result
* @return one satisfying variable assignment
* @see net.sf.javabdd.BDDDomain#set()
*/
public abstract BDD satOne(BDD var, boolean pol);
/**
* <p>Finds all satisfying variable assignments.</p>
*
* <p>Compare to bdd_allsat.</p>
*
* @return all satisfying variable assignments
*/
public abstract List allsat();
/**
* <p>Scans this BDD to find all occurrences of BDD variables and returns an
* array that contains the indices of the possible found BDD variables.</p>
*
* <p>Compare to bdd_scanset.</p>
*
* @return int[] containing indices of the possible found BDD variables
*/
public int[] scanSet() {
if (isOne() || isZero()) {
return null;
}
int num = 0;
BDD n = this.id();
do {
num++;
BDD n2 = n.high();
n.free(); n = n2;
} while (!n.isZero() && !n.isOne());
int[] varset = new int[num];
num = 0;
n = this.id();
do {
varset[num++] = n.var();
BDD n2 = n.high();
n.free(); n = n2;
} while (!n.isZero() && !n.isOne());
return varset;
}
/**
* <p>Scans this BDD and copies the stored variables into a integer array of
* BDDDomain variable numbers. The numbers returned are guaranteed to be in
* ascending order.</p>
*
* <p>Compare to fdd_scanset.</p>
*
* @return int[]
*/
public int[] scanSetDomains() {
int[] fv;
int[] varset;
int fn;
int num, n, m, i;
fv = this.scanSet();
if (fv == null)
return null;
fn = fv.length;
BDDFactory factory = getFactory();
for (n = 0, num = 0; n < factory.numberOfDomains(); n++) {
BDDDomain dom = factory.getDomain(n);
int[] ivar = dom.vars();
boolean found = false;
for (m = 0; m < dom.varNum() && !found; m++) {
for (i = 0; i < fn && !found; i++) {
if (ivar[m] == fv[i]) {
num++;
found = true;
}
}
}
}
varset = new int[num];
for (n = 0, num = 0; n < factory.numberOfDomains(); n++) {
BDDDomain dom = factory.getDomain(n);
int[] ivar = dom.vars();
boolean found = false;
for (m = 0; m < dom.varNum() && !found; m++) {
for (i = 0; i < fn && !found; i++) {
if (ivar[m] == fv[i]) {
varset[num++] = n;
found = true;
}
}
}
}
return varset;
}
/**
* <p>Finds one satisfying assignment of the domain <tt>d</tt> in this BDD
* and returns that value.</p>
*
* <p>Compare to fdd_scanvar.</p>
*
* @param d domain to scan
* @return one satisfying assignment for that domain
*/
public BigInteger scanVar(BDDDomain d) {
if (this.isZero())
return BigInteger.valueOf(-1);
BigInteger[] allvar = this.scanAllVar();
BigInteger res = allvar[d.getIndex()];
return res;
}
/**
* <p>Finds one satisfying assignment in this BDD of all the defined
* BDDDomain's. Each value is stored in an array which is returned. The size
* of this array is exactly the number of BDDDomain's defined.</p>
*
* <p>Compare to fdd_scanallvar.</p>
*
* @return array containing one satisfying assignment of all the defined domains
*/
public BigInteger[] scanAllVar() {
int n;
boolean[] store;
BigInteger[] res;
if (this.isZero())
return null;
BDDFactory factory = getFactory();
int bddvarnum = factory.varNum();
store = new boolean[bddvarnum];
BDD p = this.id();
while (!p.isOne() && !p.isZero()) {
BDD lo = p.low();
if (!lo.isZero()) {
store[p.var()] = false;
BDD p2 = p.low();
p.free(); p = p2;
} else {
store[p.var()] = true;
BDD p2 = p.high();
p.free(); p = p2;
}
lo.free();
}
int fdvarnum = factory.numberOfDomains();
res = new BigInteger[fdvarnum];
for (n = 0; n < fdvarnum; n++) {
BDDDomain dom = factory.getDomain(n);
int[] ivar = dom.vars();
BigInteger val = BigInteger.ZERO;
for (int m = dom.varNum() - 1; m >= 0; m--) {
val = val.shiftLeft(1);
if (store[ivar[m]])
val = val.add(BigInteger.ONE);
}
res[n] = val;
}
return res;
}
/**
* Utility function to convert from a BDD varset to an array of levels.
*
* @param r BDD varset
* @return array of levels
*/
private static int[] varset2levels(BDD r) {
int size = 0;
BDD p = r.id();
while (!p.isOne() && !p.isZero()) {
++size;
BDD p2 = p.high();
p.free();
p = p2;
}
p.free();
int[] result = new int[size];
size = -1;
p = r.id();
while (!p.isOne() && !p.isZero()) {
result[++size] = p.level();
BDD p2 = p.high();
p.free();
p = p2;
}
p.free();
return result;
}
/**
* <p>Returns an iteration of the satisfying assignments of this BDD. Returns
* an iteration of minterms. The <tt>var</tt> argument is the set of variables
* that will be mentioned in the result.</p>
*
* @param var set of variables to mention in result
* @return an iteration of minterms
* @see net.sf.javabdd.BDDDomain#set()
*/
public BDDIterator iterator(final BDD var) {
return new BDDIterator(this, var);
}
/**
* <p>BDDIterator is used to iterate through the satisfying assignments of a BDD.
* It includes the ability to check if bits are dont-cares and skip them.</p>
*
* @author jwhaley
* @version $Id: BDD.java,v 1.5 2005/01/26 23:46:17 joewhaley Exp $
*/
public static class BDDIterator implements Iterator {
protected BDDFactory factory;
protected int[] levels;
protected boolean[] values;
protected BDD[] nodes = null;
protected boolean more = false;
/**
* <p>Construct a new BDDIterator on the given BDD. The <tt>var</tt>
* argument is the set of variables that will be mentioned in the result.</p>
*
* @param dis BDD to iterate over
* @param var variable set to mention in result
*/
public BDDIterator(BDD dis, BDD var){
factory = dis.getFactory();
if (!dis.isZero()) {
levels = varset2levels(var);
values = new boolean[levels.length];
nodes = new BDD[levels.length];
fillInSatisfyingAssignment(dis.id(), 0);
more = true;
}
}
protected void fillInSatisfyingAssignment(BDD node, int i) {
while (!node.isOne() && !node.isZero()) {
int v = node.level();
// Mark skipped variables as dont-cares.
int j = i;
while (j < levels.length && levels[j] != v) {
if (nodes[j] != null)
throw new InternalError("nodes["+j+"] should be null");
++j;
}
if (j == levels.length) {
StringBuffer sb = new StringBuffer();
sb.append("BDD contains variable ");
sb.append(factory.level2Var(v));
sb.append("(level ");
sb.append(v);
sb.append(") not in iteration set:\n");
for (int k = 0; k < levels.length; ++k) {
sb.append(factory.level2Var(levels[k]));
if (k < levels.length-1) sb.append(",");
}
sb.append("\n(levels: ");
for (int k = 0; k < levels.length; ++k) {
sb.append(levels[k]);
if (k < levels.length-1) sb.append(",");
}
sb.append(")\n");
throw new BDDException(sb.toString());
}
i = j;
// Put node in table.
nodes[i] = node;
// Choose zero edge.
BDD node2 = node.low();
if (node2.isZero()) {
// Zero edge is F. Choose one edge instead.
node2.free();
values[i] = true;
node2 = node.high();
}
node = node2;
++i;
}
}
protected boolean findNextSatisfyingAssignment() {
int i = nodes.length - 1;
for (;;) {
if (i < 0) return false;
if (nodes[i] != null) {
if (!values[i]) {
// We already tried zero, try a one here now.
BDD hi = nodes[i].high();
if (!hi.isZero()) {
values[i] = true;
fillInSatisfyingAssignment(hi, i+1);
return true;
} else {
// Leads to zero, no satisfying assignments.
// Fallthrough.
}
}
// We already tried both zero and one.
nodes[i].free();
nodes[i] = null;
values[i] = false;
// Fallthrough: Go to next bit.
} else {
// This is a dont-care bit, skip it.
}
--i;
}
}
protected void increment() {
more = false;
boolean carry = true;
for (int i = levels.length - 1; i >= 0; --i) {
boolean val = values[i];
if (nodes[i] == null) {
if (carry) {
values[i] = !val;
more |= !val;
carry = val;
}
}
}
}
protected BDD buildAndIncrement() {
more = false;
BDD b = factory.one();
boolean carry = true;
for (int i = levels.length - 1; i >= 0; --i) {
int level = levels[i];
int var = factory.level2Var(level);
boolean val = values[i];
if (nodes[i] == null) {
if (carry) {
values[i] = !val;
more |= !val;
carry = val;
}
}
BDD v = val ? factory.ithVar(var) : factory.nithVar(var);
b.andWith(v);
}
return b;
}
protected void free() {
for (int i = levels.length - 1; i >= 0; --i) {
if (nodes[i] != null) {
nodes[i].free();
nodes[i] = null;
}
}
nodes = null;
}
/* (non-Javadoc)
* @see java.util.Iterator#next()
*/
public Object next() {
BDD b;
if (more) {
b = buildAndIncrement();
} else {
throw new NoSuchElementException();
}
if (!more) {
more = findNextSatisfyingAssignment();
if (!more) {
free();
}
}
return b;
}
/* (non-Javadoc)
* @see java.util.Iterator#hasNext()
*/
public boolean hasNext() {
return nodes != null;
}
/* (non-Javadoc)
* @see java.util.Iterator#remove()
*/
public void remove() {
throw new UnsupportedOperationException();
}
/**
* <p>Returns true if the given BDD variable number is a dont-care.
* <tt>var</tt> must be a variable in the iteration set.</p>
*
* @param var variable number to check
* @return if the given variable is a dont-care
* @throws BDDException if var is not in the iteration set
*/
public boolean isDontCare(int var) {
if (nodes == null) return false;
if (levels == null)
throw new BDDException();
int level = factory.var2Level(var);
int i = Arrays.binarySearch(levels, level);
if (i < 0)
throw new BDDException("var "+var+" not in iteration set");
return nodes[i] == null;
}
/**
* <p>Returns true if the BDD variables in the given BDD domain are
* all dont-care's.<p>
*
* @param d domain to check
* @return if the variables are all dont-cares
* @throws BDDException if d is not in the iteration set
*/
public boolean isDontCare(BDDDomain d) {
if (nodes == null) return false;
int[] vars = d.vars();
for (int i = 0; i < vars.length; ++i) {
if (!isDontCare(vars[i])) return false;
}
return true;
}
protected void fastForward0(int var) {
if (levels == null)
throw new BDDException();
int level = factory.var2Level(var);
int i = Arrays.binarySearch(levels, level);
if (i < 0)
throw new BDDException();
if (nodes[i] != null)
throw new BDDException();
values[i] = true;
}
/**
* Fast-forward the iteration such that the given variable number is true.
*
* @param var number of variable
*/
public void fastForward(int var) {
fastForward0(var);
//increment();
}
/**
* Assuming <tt>d</tt> is a dont-care, skip to the end of the iteration for
* <tt>d</tt>
*
* @param d BDD domain to fast-forward past
*/
public void skipDontCare(BDDDomain d) {
int[] vars = d.vars();
for (int i = 0; i < vars.length; ++i) {
fastForward0(vars[i]);
}
//increment();
}
}
/**
* <p>This is another version of iterator() that supports the remove() operation.
* It is much slower than the other one.</p>
*
* @return an iteration of minterms
*/
public Iterator iterator2(final BDD var) {
return new Iterator() {
BDD b = null;
BDD myVar;
BDD last = null;
{
if (!isZero()) {
b = id();
myVar = var.id();
}
}
/* (non-Javadoc)
* @see java.util.Iterator#remove()
*/
public void remove() {
if (last != null) {
applyWith(last.id(), BDDFactory.diff);
last = null;
} else {
throw new IllegalStateException();
}
}
/* (non-Javadoc)
* @see java.util.Iterator#hasNext()
*/
public boolean hasNext() {
return b != null;
}
/* (non-Javadoc)
* @see java.util.Iterator#next()
*/
public Object next() {
if (b == null)
throw new NoSuchElementException();
BDD c = b.satOne(myVar, false);
b.applyWith(c.id(), BDDFactory.diff);
if (b.isZero()) {
myVar.free(); myVar = null;
b.free(); b = null;
}
return last = c;
}
};
}
/**
* <p>Returns a BDD where all variables are replaced with the variables
* defined by pair. Each entry in pair consists of a old and a new variable.
* Whenever the old variable is found in this BDD then a new node with
* the new variable is inserted instead.</p>
*
* <p>Compare to bdd_replace.</p>
*
* @param pair pairing of variables to the BDDs that replace those variables
* @return result of replace
*/
public abstract BDD replace(BDDPairing pair);
/**
* <p>Replaces all variables in this BDD with the variables defined by pair.
* Each entry in pair consists of a old and a new variable. Whenever the
* old variable is found in this BDD then a new node with the new variable
* is inserted instead. Mutates the current BDD.</p>
*
* <p>Compare to bdd_replace and bdd_delref.</p>
*
* @param pair pairing of variables to the BDDs that replace those variables
*/
public abstract BDD replaceWith(BDDPairing pair);
/**
* <p>Prints the set of truth assignments specified by this BDD.</p>
*
* <p>Compare to bdd_printset.</p>
*/
public void printSet() {
System.out.println(this.toString());
}
/**
* <p>Prints this BDD using a set notation as in printSet() but with the index
* of the finite domain blocks included instead of the BDD variables.</p>
*
* <p>Compare to fdd_printset.</p>
*/
public void printSetWithDomains() {
System.out.println(toStringWithDomains());
}
/**
* <p>Prints this BDD in dot graph notation.</p>
*
* <p>Compare to bdd_printdot.</p>
*/
public void printDot() {
PrintStream out = System.out;
out.println("digraph G {");
out.println("0 [shape=box, label=\"0\", style=filled, shape=box, height=0.3, width=0.3];");
out.println("1 [shape=box, label=\"1\", style=filled, shape=box, height=0.3, width=0.3];");
boolean[] visited = new boolean[nodeCount()+4];
visited[0] = true; visited[1] = true;
HashMap map = new HashMap();
map.put(getFactory().zero(), new Integer(0));
map.put(getFactory().one(), new Integer(1));
printdot_rec(out, 1, visited, map);
for (Iterator i = map.keySet().iterator(); i.hasNext(); ) {
BDD b = (BDD) i.next();
b.free();
}
out.println("}");
}
protected int printdot_rec(PrintStream out, int current, boolean[] visited, HashMap map) {
Integer ri = ((Integer) map.get(this));
if (ri == null) {
map.put(this.id(), ri = new Integer(++current));
}
int r = ri.intValue();
if (visited[r])
return current;
visited[r] = true;
// TODO: support labelling of vars.
out.println(r+" [label=\""+this.var()+"\"];");
BDD l = this.low(), h = this.high();
Integer li = ((Integer) map.get(l));
if (li == null) {
map.put(l.id(), li = new Integer(++current));
}
int low = li.intValue();
Integer hi = ((Integer) map.get(h));
if (hi == null) {
map.put(h.id(), hi = new Integer(++current));
}
int high = hi.intValue();
out.println(r+" -> "+low+" [style=dotted];");
out.println(r+" -> "+high+" [style=filled];");
current = l.printdot_rec(out, current, visited, map);
l.free();
current = h.printdot_rec(out, current, visited, map);
h.free();
return current;
}
private StringBuffer dotOut;
public String dotToString() {
dotOut = new StringBuffer();
PrintStream out = System.out;
dotOut = dotOut.append(" aa Index=0 False aa ");
dotOut = dotOut.append("Index=1 True aa ");
boolean[] visited = new boolean[(nodeCount()*2)+2];
visited[0] = true; visited[1] = true;
HashMap map = new HashMap();
map.put(getFactory().zero(), new Integer(0));
map.put(getFactory().one(), new Integer(1));
dotToString_rec(dotOut, out, 1, visited, map);
for (Iterator i = map.keySet().iterator(); i.hasNext(); ) {
BDD b = (BDD) i.next();
b.free();
}
return dotOut.toString();
}
public int dotToString_rec(StringBuffer dotOut, PrintStream out, int current, boolean[] visited, HashMap map) {
Integer ri = ((Integer) map.get(this));
if(ri == null) {
map.put(this.id(), ri = new Integer(++current));
}
int r = ri.intValue();
try {
if(visited[r]) {
return current;
}
} catch(ArrayIndexOutOfBoundsException e) {
System.out.println("CURRENT=" + current);
System.out.println("VISITED SIZE=" + visited.length);
System.exit(666);
/*
for(int i = 0; i<visited.length; i++) {
if(visited[i]==false) {
current = i;
break;
}
}
return current;
**/
}
visited[r] = true;
//out.println(r+" [label=\""+v+"\"];");
if(dotOut == null) {
System.out.println("DOT OUT IS NULL");
} else {
dotOut = dotOut.append("Index=" + r + " Variable=" + this.var() + " aa ");
}
BDD l = this.low(), h = this.high();
Integer li = ((Integer) map.get(l));
if (li == null) {
map.put(l.id(), li = new Integer(++current));
}
int low = li.intValue();
Integer hi = ((Integer) map.get(h));
if (hi == null) {
map.put(h.id(), hi = new Integer(++current));
}
int high = hi.intValue();
//out.println(r+" -> "+low+" [style=dotted];");
dotOut = dotOut.append("FLink=" + r + ":" + low + " aa ");
//out.println(r+" -> "+high+" [style=filled];");
dotOut = dotOut.append("TLink=" + r + ":" + high + " aa ");
current = l.dotToString_rec(dotOut, out, current, visited, map);
l.free();
current = h.dotToString_rec(dotOut, out, current, visited, map);
h.free();
return current;
}
/**
* <p>Counts the number of distinct nodes used for this BDD.</p>
*
* <p>Compare to bdd_nodecount.</p>
*
* @return the number of distinct nodes used for this BDD
*/
public abstract int nodeCount();
/**
* <p>Counts the number of paths leading to the true terminal.</p>
*
* <p>Compare to bdd_pathcount.</p>
*
* @return the number of paths leading to the true terminal
*/
public abstract double pathCount();
/**
* <p>Calculates the number of satisfying variable assignments.</p>
*
* <p>Compare to bdd_satcount.</p>
*
* @return the number of satisfying variable assignments
*/
public abstract double satCount();
/**
* <p>Calculates the number of satisfying variable assignments to the variables
* in the given varset. ASSUMES THAT THE BDD DOES NOT HAVE ANY ASSIGNMENTS TO
* VARIABLES THAT ARE NOT IN VARSET. You will need to quantify out the other
* variables first.</p>
*
* <p>Compare to bdd_satcountset.</p>
*
* @return the number of satisfying variable assignments
*/
public double satCount(BDD varset) {
BDDFactory factory = getFactory();
double unused = factory.varNum();
if (varset.isZero() || varset.isOne() || isZero()) /* empty set */
return 0.;
BDD n = varset.id();
do {
BDD n2 = n.high();
n.free(); n = n2;
unused--;
} while (!n.isOne() && !n.isZero());
n.free();
unused = satCount() / Math.pow(2.0, unused);
return unused >= 1.0 ? unused : 1.0;
}
/**
* <p>Calculates the logarithm of the number of satisfying variable assignments.</p>
*
* <p>Compare to bdd_satcount.</p>
*
* @return the logarithm of the number of satisfying variable assignments
*/
public double logSatCount() {
return Math.log(satCount());
}
/**
* <p>Calculates the logarithm of the number of satisfying variable assignments to the
* variables in the given varset.</p>
*
* <p>Compare to bdd_satcountset.</p>
*
* @return the logarithm of the number of satisfying variable assignments
*/
public double logSatCount(BDD varset) {
return Math.log(satCount(varset));
}
/**
* <p>Counts the number of times each variable occurs in this BDD. The
* result is stored and returned in an integer array where the i'th
* position stores the number of times the i'th printing variable
* occurred in the BDD.</p>
*
* <p>Compare to bdd_varprofile.</p>
*/
public abstract int[] varProfile();
/**
* <p>Returns true if this BDD equals that BDD, false otherwise.</p>
*
* @param that the BDD to compare with
* @return true iff the two BDDs are equal
*/
public abstract boolean equals(BDD that);
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object o) {
if (!(o instanceof BDD)) return false;
return this.equals((BDD) o);
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
public abstract int hashCode();
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
public String toString() {
// -----------------------------------------------------------------------------------
BDDFactory f = this.getFactory();
System.out.println("SET SIZE DECLARATION: " + f.varNum());
int[] set = new int[f.varNum()];
StringBuffer sb = new StringBuffer();
bdd_printset_rec(f, sb, this, set);
return sb.toString();
// -----------------------------------------------------------------------------------
}
private static void bdd_printset_rec(BDDFactory f, StringBuffer sb, BDD r, int[] set) {
int n;
boolean first;
if (r.isZero())
return;
else if (r.isOne()) {
sb.append('<');
first = true;
for (n = 0; n < set.length; n++) {
if (set[n] > 0) {
if (!first)
sb.append(", ");
first = false;
sb.append(f.level2Var(n));
sb.append(':');
sb.append((set[n] == 2 ? 1 : 0));
}
}
sb.append('>');
} else {
// -----------------------------------------------------------------------
//System.out.println("INDEX: " + (f.var2Level(r.var())-1));
//System.out.println("SIZE: " + set.length);
// -----------------------------------------------------------------------
set[f.var2Level(r.var())-1] = 1;
BDD rl = r.low();
bdd_printset_rec(f, sb, rl, set);
rl.free();
set[f.var2Level(r.var())-1] = 2;
BDD rh = r.high();
bdd_printset_rec(f, sb, rh, set);
rh.free();
set[f.var2Level(r.var())-1] = 0;
}
}
/**
* <p>Returns a string representation of this BDD using the defined domains.</p>
*
* @return string representation of this BDD using the defined domains
*/
public String toStringWithDomains() {
return toStringWithDomains(BDDToString.INSTANCE);
}
/**
* <p>Returns a string representation of this BDD on the defined domains,
* using the given BDDToString converter.</p>
*
* @see net.sf.javabdd.BDD.BDDToString
*
* @return string representation of this BDD using the given BDDToString converter
*/
public String toStringWithDomains(BDDToString ts) {
if (this.isZero()) return "F";
if (this.isOne()) return "T";
BDDFactory bdd = getFactory();
StringBuffer sb = new StringBuffer();
int[] set = new int[bdd.varNum()];
fdd_printset_rec(bdd, sb, ts, this, set);
return sb.toString();
}
private static class OutputBuffer {
BDDToString ts;
StringBuffer sb;
int domain;
BigInteger lastLow;
BigInteger lastHigh;
boolean done;
static final BigInteger MINUS2 = BigInteger.valueOf(-2);
OutputBuffer(BDDToString ts, StringBuffer sb, int domain) {
this.ts = ts;
this.sb = sb;
this.lastHigh = MINUS2;
this.domain = domain;
}
void append(BigInteger low, BigInteger high) {
if (low.equals(lastHigh.add(BigInteger.ONE))) {
lastHigh = high;
} else {
finish();
lastLow = low; lastHigh = high;
}
}
StringBuffer finish() {
if (!lastHigh.equals(MINUS2)) {
if (done) sb.append('/');
if (lastLow.equals(lastHigh))
sb.append(ts.elementName(domain, lastHigh));
else
sb.append(ts.elementNames(domain, lastLow, lastHigh));
lastHigh = MINUS2;
}
done = true;
return sb;
}
void append(BigInteger low) {
append(low, low);
}
}
private static void fdd_printset_helper(OutputBuffer sb,
BigInteger value, int i,
int[] set, int[] var,
int maxSkip) {
if (i == maxSkip) {
//_assert(set[var[i]] == 0);
BigInteger maxValue = value.or(BigInteger.ONE.shiftLeft(i+1).subtract(BigInteger.ONE));
sb.append(value, maxValue);
return;
}
int val = set[var[i]];
if (val == 0) {
BigInteger temp = value.setBit(i);
fdd_printset_helper(sb, temp, i-1, set, var, maxSkip);
}
fdd_printset_helper(sb, value, i-1, set, var, maxSkip);
}
private static void fdd_printset_rec(BDDFactory bdd, StringBuffer sb, BDDToString ts, BDD r, int[] set) {
int fdvarnum = bdd.numberOfDomains();
int n, m, i;
boolean used = false;
int[] var;
boolean first;
if (r.isZero())
return;
else if (r.isOne()) {
sb.append('<');
first = true;
for (n=0 ; n<fdvarnum ; n++) {
used = false;
BDDDomain domain_n = bdd.getDomain(n);
int[] domain_n_ivar = domain_n.vars();
int domain_n_varnum = domain_n_ivar.length;
for (m=0 ; m<domain_n_varnum ; m++)
if (set[domain_n_ivar[m]] != 0)
used = true;
if (used) {
if (!first)
sb.append(", ");
first = false;
sb.append(domain_n.getName());
sb.append(':');
var = domain_n_ivar;
BigInteger pos = BigInteger.ZERO;
int maxSkip = -1;
boolean hasDontCare = false;
for (i=0; i<domain_n_varnum; ++i) {
int val = set[var[i]];
if (val == 0) {
hasDontCare = true;
if (maxSkip == i-1)
maxSkip = i;
}
}
for (i=domain_n_varnum-1; i>=0; --i) {
pos = pos.shiftLeft(1);
int val = set[var[i]];
if (val == 2) {
pos = pos.setBit(0);
}
}
if (!hasDontCare) {
sb.append(ts.elementName(n, pos));
} else {
OutputBuffer ob = new OutputBuffer(ts, sb, n);
fdd_printset_helper(ob, pos, domain_n_varnum-1,
set, var, maxSkip);
ob.finish();
}
}
}
sb.append('>');
} else {
set[r.var()] = 1;
BDD lo = r.low();
fdd_printset_rec(bdd, sb, ts, lo, set);
lo.free();
set[r.var()] = 2;
BDD hi = r.high();
fdd_printset_rec(bdd, sb, ts, hi, set);
hi.free();
set[r.var()] = 0;
}
}
/**
* <p>BDDToString is used to specify the printing behavior of BDDs with domains.
* Subclass this type and pass it as an argument to toStringWithDomains to
* have the toStringWithDomains function use your domain names and element names,
* instead of just numbers.</p>
*/
public static class BDDToString {
/**
* <p>Singleton instance that does the default behavior: domains and
* elements are printed as their numbers.</p>
*/
public static final BDDToString INSTANCE = new BDDToString();
/**
* <p>Protected constructor.</p>
*/
protected BDDToString() { }
/**
* <p>Given a domain index and an element index, return the element's name.
* Called by the toStringWithDomains() function.</p>
*
* @param i the domain number
* @param j the element number
* @return the string representation of that element
*/
public String elementName(int i, BigInteger j) {
return j.toString();
}
/**
* <p>Given a domain index and an inclusive range of element indices,
* return the names of the elements in that range.
* Called by the toStringWithDomains() function.</p>
*
* @param i the domain number
* @param lo the low range of element numbers, inclusive
* @param hi the high range of element numbers, inclusive
* @return the string representation of the elements in the range
*/
public String elementNames(int i, BigInteger lo, BigInteger hi) {
return lo.toString()+"-"+hi.toString();
}
}
/**
* <p>Frees this BDD. Further use of this BDD will result in an exception being thrown.</p>
*/
public abstract void free();
/**
* <p>Protected constructor.</p>
*/
protected BDD() { }
}