You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
832 lines
23 KiB
832 lines
23 KiB
/**
|
|
@file
|
|
|
|
@ingroup cplusplus
|
|
|
|
@brief Test program for the C++ object-oriented encapsulation of CUDD.
|
|
|
|
@author Fabio Somenzi
|
|
|
|
@copyright@parblock
|
|
Copyright (c) 1995-2015, Regents of the University of Colorado
|
|
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions
|
|
are met:
|
|
|
|
Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
Neither the name of the University of Colorado nor the names of its
|
|
contributors may be used to endorse or promote products derived from
|
|
this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
@endparblock
|
|
|
|
*/
|
|
|
|
#include "cuddObj.hh"
|
|
#include <math.h>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <cassert>
|
|
#include <stdexcept>
|
|
|
|
using namespace std;
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Variable declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Static function prototypes */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static void testBdd(Cudd& mgr, int verbosity);
|
|
static void testAdd(Cudd& mgr, int verbosity);
|
|
static void testAdd2(Cudd& mgr, int verbosity);
|
|
static void testZdd(Cudd& mgr, int verbosity);
|
|
static void testBdd2(Cudd& mgr, int verbosity);
|
|
static void testBdd3(Cudd& mgr, int verbosity);
|
|
static void testZdd2(Cudd& mgr, int verbosity);
|
|
static void testBdd4(Cudd& mgr, int verbosity);
|
|
static void testBdd5(Cudd& mgr, int verbosity);
|
|
static void testInterpolation(Cudd& mgr, int verbosity);
|
|
static void testErrorHandling(Cudd& mgr, int verbosity);
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Definition of exported functions */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
@brief Main program for testobj.
|
|
*/
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
int verbosity = 0;
|
|
|
|
if (argc == 2) {
|
|
int cnt;
|
|
int retval = sscanf(argv[1], "%d %n", &verbosity, &cnt);
|
|
if (retval != 1 || argv[1][cnt])
|
|
return 1;
|
|
} else if (argc != 1) {
|
|
return 1;
|
|
}
|
|
|
|
Cudd mgr(0,2);
|
|
if (verbosity > 2) mgr.makeVerbose(); // trace constructors and destructors
|
|
testBdd(mgr,verbosity);
|
|
testAdd(mgr,verbosity);
|
|
testAdd2(mgr,verbosity);
|
|
testZdd(mgr,verbosity);
|
|
testBdd2(mgr,verbosity);
|
|
testBdd3(mgr,verbosity);
|
|
testZdd2(mgr,verbosity);
|
|
testBdd4(mgr,verbosity);
|
|
testBdd5(mgr,verbosity);
|
|
testInterpolation(mgr,verbosity);
|
|
testErrorHandling(mgr,verbosity);
|
|
if (verbosity) mgr.info();
|
|
return 0;
|
|
|
|
} // main
|
|
|
|
|
|
/**
|
|
@brief Test basic operators on BDDs.
|
|
|
|
@details The function returns void
|
|
because it relies on the error handling done by the interface. The
|
|
default error handler causes program termination.
|
|
|
|
@sideeffect Creates BDD variables in the manager.
|
|
|
|
@see testBdd2 testBdd3 testBdd4 testBdd5
|
|
|
|
*/
|
|
static void
|
|
testBdd(
|
|
Cudd& mgr,
|
|
int verbosity)
|
|
{
|
|
if (verbosity) cout << "Entering testBdd\n";
|
|
// Create two new variables in the manager. If testBdd is called before
|
|
// any variable is created in mgr, then x gets index 0 and y gets index 1.
|
|
BDD x = mgr.bddVar();
|
|
BDD y = mgr.bddVar();
|
|
|
|
BDD f = x * y;
|
|
if (verbosity) cout << "f"; f.print(2,verbosity);
|
|
|
|
BDD g = y + !x;
|
|
if (verbosity) cout << "g"; g.print(2,verbosity);
|
|
|
|
if (verbosity)
|
|
cout << "f and g are" << (f == !g ? "" : " not") << " complementary\n";
|
|
if (verbosity)
|
|
cout << "f is" << (f <= g ? "" : " not") << " less than or equal to g\n";
|
|
|
|
g = f | ~g;
|
|
if (verbosity) cout << "g"; g.print(2,verbosity);
|
|
|
|
BDD h = f = y;
|
|
if (verbosity) cout << "h"; h.print(2,verbosity);
|
|
|
|
if (verbosity) cout << "x + h has " << (x+h).nodeCount() << " nodes\n";
|
|
|
|
h += x;
|
|
if (verbosity) cout << "h"; h.print(2,verbosity);
|
|
|
|
} // testBdd
|
|
|
|
|
|
/**
|
|
@brief Test basic operators on ADDs.
|
|
|
|
@details The function returns void because it relies on the error
|
|
handling done by the interface. The default error handler causes
|
|
program termination.
|
|
|
|
@sideeffect May create ADD variables in the manager.
|
|
|
|
@see testAdd2
|
|
|
|
*/
|
|
static void
|
|
testAdd(
|
|
Cudd& mgr,
|
|
int verbosity)
|
|
{
|
|
if (verbosity) cout << "Entering testAdd\n";
|
|
// Create two ADD variables. If we called method addVar without an
|
|
// argument, we would get two new indices. If testAdd is indeed called
|
|
// after testBdd, then those indices would be 2 and 3. By specifying the
|
|
// arguments, on the other hand, we avoid creating new unnecessary BDD
|
|
// variables.
|
|
ADD p = mgr.addVar(0);
|
|
ADD q = mgr.addVar(1);
|
|
|
|
// Test arithmetic operators.
|
|
ADD r = p + q;
|
|
if (verbosity) cout << "r"; r.print(2,verbosity);
|
|
|
|
// CUDD_VALUE_TYPE is double.
|
|
ADD s = mgr.constant(3.0);
|
|
s *= p * q;
|
|
if (verbosity) cout << "s"; s.print(2,verbosity);
|
|
|
|
s += mgr.plusInfinity();
|
|
if (verbosity) cout << "s"; s.print(2,verbosity);
|
|
|
|
// Test relational operators.
|
|
if (verbosity)
|
|
cout << "p is" << (p <= r ? "" : " not") << " less than or equal to r\n";
|
|
|
|
// Test logical operators.
|
|
r = p | q;
|
|
if (verbosity) cout << "r"; r.print(2,verbosity);
|
|
|
|
} // testAdd
|
|
|
|
|
|
/**
|
|
@brief Test some more operators on ADDs.
|
|
|
|
@details The function returns void because it relies on the error
|
|
handling done by the interface. The default error handler causes
|
|
program termination.
|
|
|
|
@sideeffect May create ADD variables in the manager.
|
|
|
|
@see testAdd
|
|
|
|
*/
|
|
static void
|
|
testAdd2(
|
|
Cudd& mgr,
|
|
int verbosity)
|
|
{
|
|
if (verbosity) cout << "Entering testAdd2\n";
|
|
// Create two ADD variables. If we called method addVar without an
|
|
// argument, we would get two new indices.
|
|
vector<ADD> x(2);
|
|
for (size_t i = 0; i < 2; ++i) {
|
|
x[i] = mgr.addVar((int) i);
|
|
}
|
|
|
|
// Build a probability density function: [0.1, 0.2, 0.3, 0.4].
|
|
ADD f0 = x[1].Ite(mgr.constant(0.2), mgr.constant(0.1));
|
|
ADD f1 = x[1].Ite(mgr.constant(0.4), mgr.constant(0.3));
|
|
ADD f = x[0].Ite(f1, f0);
|
|
if (verbosity) cout << "f"; f.print(2,verbosity);
|
|
|
|
// Compute the entropy.
|
|
ADD l = f.Log();
|
|
if (verbosity) cout << "l"; l.print(2,verbosity);
|
|
ADD r = f * l;
|
|
if (verbosity) cout << "r"; r.print(2,verbosity);
|
|
|
|
ADD e = r.MatrixMultiply(mgr.constant(-1.0/log(2.0)),x);
|
|
if (verbosity) cout << "e"; e.print(2,verbosity);
|
|
|
|
} // testAdd2
|
|
|
|
|
|
/**
|
|
@brief Test basic operators on ZDDs.
|
|
|
|
@details The function returns void because it relies on the error
|
|
handling done by the interface. The default error handler causes
|
|
program termination.
|
|
|
|
@sideeffect May create ZDD variables in the manager.
|
|
|
|
@see testZdd2
|
|
|
|
*/
|
|
static void
|
|
testZdd(
|
|
Cudd& mgr,
|
|
int verbosity)
|
|
{
|
|
if (verbosity) cout << "Entering testZdd\n";
|
|
ZDD v = mgr.zddVar(0);
|
|
ZDD w = mgr.zddVar(1);
|
|
|
|
ZDD s = v + w;
|
|
if (verbosity) cout << "s"; s.print(2,verbosity);
|
|
|
|
if (verbosity) cout << "v is" << (v < s ? "" : " not") << " less than s\n";
|
|
|
|
s -= v;
|
|
if (verbosity) cout << "s"; s.print(2,verbosity);
|
|
|
|
} // testZdd
|
|
|
|
|
|
/**
|
|
@brief Test vector operators on BDDs.
|
|
|
|
@details The function returns void because it relies on the error
|
|
handling done by the interface. The default error handler causes
|
|
program termination.
|
|
|
|
@sideeffect May create BDD variables in the manager.
|
|
|
|
@see testBdd testBdd3 testBdd4 testBdd5
|
|
|
|
*/
|
|
static void
|
|
testBdd2(
|
|
Cudd& mgr,
|
|
int verbosity)
|
|
{
|
|
if (verbosity) cout << "Entering testBdd2\n";
|
|
vector<BDD> x(4);
|
|
for (size_t i = 0; i < 4; ++i) {
|
|
x[i] = mgr.bddVar((int) i);
|
|
}
|
|
|
|
// Create the BDD for the Achilles' Heel function.
|
|
BDD p1 = x[0] * x[2];
|
|
BDD p2 = x[1] * x[3];
|
|
BDD f = p1 + p2;
|
|
const char* inames[] = {"x0", "x1", "x2", "x3"};
|
|
if (verbosity) {
|
|
cout << "f"; f.print(4,verbosity);
|
|
cout << "Irredundant cover of f:" << endl; f.PrintCover();
|
|
cout << "Number of minterms (arbitrary precision): "; f.ApaPrintMinterm(4);
|
|
cout << "Number of minterms (extended precision): "; f.EpdPrintMinterm(4);
|
|
cout << "Two-literal clauses of f:" << endl;
|
|
f.PrintTwoLiteralClauses((char **)inames); cout << endl;
|
|
}
|
|
|
|
vector<BDD> vect = f.CharToVect();
|
|
if (verbosity) {
|
|
for (size_t i = 0; i < vect.size(); i++) {
|
|
cout << "vect[" << i << "]" << endl; vect[i].PrintCover();
|
|
}
|
|
}
|
|
|
|
// v0,...,v3 suffice if testBdd2 is called before testBdd3.
|
|
if (verbosity) {
|
|
const char* onames[] = {"v0", "v1", "v2", "v3", "v4", "v5"};
|
|
mgr.DumpDot(vect, (char **)inames,(char **)onames);
|
|
}
|
|
|
|
} // testBdd2
|
|
|
|
|
|
/**
|
|
@brief Test additional operators on BDDs.
|
|
|
|
@details The function returns void because it relies on the error
|
|
handling done by the interface. The default error handler causes
|
|
program termination.
|
|
|
|
@sideeffect May create BDD variables in the manager.
|
|
|
|
@see testBdd testBdd2 testBdd4 testBdd5
|
|
|
|
*/
|
|
static void
|
|
testBdd3(
|
|
Cudd& mgr,
|
|
int verbosity)
|
|
{
|
|
if (verbosity) cout << "Entering testBdd3\n";
|
|
vector<BDD> x(6);
|
|
for (size_t i = 0; i < 6; ++i) {
|
|
x[i] = mgr.bddVar((int) i);
|
|
}
|
|
|
|
BDD G = x[4] + !x[5];
|
|
BDD H = x[4] * x[5];
|
|
BDD E = x[3].Ite(G,!x[5]);
|
|
BDD F = x[3] + !H;
|
|
BDD D = x[2].Ite(F,!H);
|
|
BDD C = x[2].Ite(E,!F);
|
|
BDD B = x[1].Ite(C,!F);
|
|
BDD A = x[0].Ite(B,!D);
|
|
BDD f = !A;
|
|
if (verbosity) cout << "f"; f.print(6,verbosity);
|
|
|
|
BDD f1 = f.RemapUnderApprox(6);
|
|
if (verbosity) cout << "f1"; f1.print(6,verbosity);
|
|
if (verbosity)
|
|
cout << "f1 is" << (f1 <= f ? "" : " not") << " less than or equal to f\n";
|
|
|
|
BDD g;
|
|
BDD h;
|
|
f.GenConjDecomp(&g,&h);
|
|
if (verbosity) {
|
|
cout << "g"; g.print(6,verbosity);
|
|
cout << "h"; h.print(6,verbosity);
|
|
cout << "g * h " << (g * h == f ? "==" : "!=") << " f\n";
|
|
}
|
|
|
|
} // testBdd3
|
|
|
|
|
|
/**
|
|
@brief Test cover manipulation with BDDs and ZDDs.
|
|
|
|
@details The function returns void because it relies on the error
|
|
handling done by the interface. The default error handler causes
|
|
program termination. This function builds the BDDs for a
|
|
transformed adder: one in which the inputs are transformations of
|
|
the original inputs. It then creates ZDDs for the covers from the
|
|
BDDs.
|
|
|
|
@sideeffect May create BDD and ZDD variables in the manager.
|
|
|
|
@see testZdd
|
|
|
|
*/
|
|
static void
|
|
testZdd2(
|
|
Cudd& mgr,
|
|
int verbosity)
|
|
{
|
|
if (verbosity) cout << "Entering testZdd2\n";
|
|
size_t N = 3; // number of bits
|
|
// Create variables.
|
|
vector<BDD> a(N);
|
|
vector<BDD> b(N);
|
|
vector<BDD> c(N+1);
|
|
for (size_t i = 0; i < N; ++i) {
|
|
a[N-1-i] = mgr.bddVar(2*(int)i);
|
|
b[N-1-i] = mgr.bddVar(2*(int)i+1);
|
|
}
|
|
c[0] = mgr.bddVar(2*(int)N);
|
|
// Build functions.
|
|
vector<BDD> s(N);
|
|
for (size_t i = 0; i < N; ++i) {
|
|
s[i] = a[i].Xnor(c[i]);
|
|
c[i+1] = a[i].Ite(b[i],c[i]);
|
|
}
|
|
|
|
// Create array of outputs and print it.
|
|
vector<BDD> p(N+1);
|
|
for (size_t i = 0; i < N; ++i) {
|
|
p[i] = s[i];
|
|
}
|
|
p[N] = c[N];
|
|
if (verbosity) {
|
|
for (size_t i = 0; i < p.size(); ++i) {
|
|
cout << "p[" << i << "]"; p[i].print(2*(int)N+1,verbosity);
|
|
}
|
|
}
|
|
const char* onames[] = {"s0", "s1", "s2", "c3"};
|
|
if (verbosity) {
|
|
const char* inames[] = {"a2", "b2", "a1", "b1", "a0", "b0", "c0"};
|
|
mgr.DumpDot(p, (char **)inames,(char **)onames);
|
|
}
|
|
|
|
// Create ZDD variables and build ZDD covers from BDDs.
|
|
mgr.zddVarsFromBddVars(2);
|
|
vector<ZDD> z(N+1);
|
|
for (size_t i = 0; i < N+1; ++i) {
|
|
ZDD temp;
|
|
BDD dummy = p[i].zddIsop(p[i],&temp);
|
|
z[i] = temp;
|
|
}
|
|
|
|
// Print out covers.
|
|
if (verbosity) {
|
|
DdGen *gen;
|
|
int *path;
|
|
for (size_t i = 0; i < z.size(); i++) {
|
|
cout << "z[" << i << "]"; z[i].print(4*(int)N+2,verbosity);
|
|
}
|
|
// Print cover in two different ways: with PrintCover and with
|
|
// enumeration over the paths. The only difference should be
|
|
// a reversal in the order of the cubes.
|
|
for (size_t i = 0; i < z.size(); i++) {
|
|
cout << "z[" << i << "]\n"; z[i].PrintCover();
|
|
cout << "z[" << i << "]\n";
|
|
DdNode *f = Cudd_Not(z[i].getNode());
|
|
Cudd_zddForeachPath(z[i].manager(), f, gen, path) {
|
|
for (size_t q = 0; q < 4*N+2; q += 2) {
|
|
int v = path[q] * 4 + path[q+1];
|
|
switch (v) {
|
|
case 0:
|
|
case 2:
|
|
case 8:
|
|
case 10:
|
|
cout << "-";
|
|
break;
|
|
case 1:
|
|
case 9:
|
|
cout << "0";
|
|
break;
|
|
case 6:
|
|
cout << "1";
|
|
break;
|
|
default:
|
|
cout << "?";
|
|
}
|
|
}
|
|
cout << " 1\n";
|
|
}
|
|
}
|
|
const char* znames[] = {"a2+", "a2-", "b2+", "b2-", "a1+", "a1-", "b1+",
|
|
"b1-", "a0+", "a0-", "b0+", "b0-", "c0+", "c0-"};
|
|
mgr.DumpDot(z, (char **)znames,(char **)onames);
|
|
}
|
|
|
|
} // testZdd2
|
|
|
|
|
|
/**
|
|
@brief Test transfer between BDD managers.
|
|
|
|
@details The function returns void because it relies on the error
|
|
handling done by the interface. The default error handler causes
|
|
program termination.
|
|
|
|
@sideeffect May create BDD variables in the manager.
|
|
|
|
@see testBdd testBdd2 testBdd3 testBdd5
|
|
|
|
*/
|
|
static void
|
|
testBdd4(
|
|
Cudd& mgr,
|
|
int verbosity)
|
|
{
|
|
if (verbosity) cout << "Entering testBdd4\n";
|
|
BDD x = mgr.bddVar(0);
|
|
BDD y = mgr.bddVar(1);
|
|
BDD z = mgr.bddVar(2);
|
|
|
|
BDD f = (~x & ~y & ~z) | (x & y);
|
|
if (verbosity) cout << "f"; f.print(3,verbosity);
|
|
|
|
Cudd otherMgr(0,0);
|
|
BDD g = f.Transfer(otherMgr);
|
|
if (verbosity) cout << "g"; g.print(3,verbosity);
|
|
|
|
BDD h = g.Transfer(mgr);
|
|
if (verbosity)
|
|
cout << "f and h are" << (f == h ? "" : " not") << " identical\n";
|
|
|
|
} // testBdd4
|
|
|
|
|
|
/**
|
|
@brief Test maximal expansion of cubes.
|
|
|
|
@details The function returns void because it relies on the error
|
|
handling done by the interface. The default error handler causes
|
|
program termination.
|
|
|
|
@sideeffect May create BDD variables in the manager.
|
|
|
|
@see testBdd testBdd2 testBdd3 testBdd4
|
|
|
|
*/
|
|
static void
|
|
testBdd5(
|
|
Cudd& mgr,
|
|
int verbosity)
|
|
{
|
|
if (verbosity) cout << "Entering testBdd5\n";
|
|
vector<BDD> x;
|
|
x.reserve(4);
|
|
for (int i = 0; i < 4; i++) {
|
|
x.push_back(mgr.bddVar(i));
|
|
}
|
|
const char* inames[] = {"a", "b", "c", "d"};
|
|
BDD f = (x[1] & x[3]) | (x[0] & ~x[2] & x[3]) | (~x[0] & x[1] & ~x[2]);
|
|
BDD lb = x[1] & ~x[2] & x[3];
|
|
BDD ub = x[3];
|
|
BDD primes = lb.MaximallyExpand(ub,f);
|
|
assert(primes == (x[1] & x[3]));
|
|
BDD lprime = primes.LargestPrimeUnate(lb);
|
|
assert(lprime == primes);
|
|
if (verbosity) {
|
|
const char * onames[] = {"lb", "ub", "f", "primes", "lprime"};
|
|
vector<BDD> z;
|
|
z.reserve(5);
|
|
z.push_back(lb);
|
|
z.push_back(ub);
|
|
z.push_back(f);
|
|
z.push_back(primes);
|
|
z.push_back(lprime);
|
|
mgr.DumpDot(z, (char **)inames, (char **)onames);
|
|
cout << "primes(1)"; primes.print(4,verbosity);
|
|
}
|
|
|
|
lb = ~x[0] & x[2] & x[3];
|
|
primes = lb.MaximallyExpand(ub,f);
|
|
assert(primes == mgr.bddZero());
|
|
if (verbosity) {
|
|
cout << "primes(2)"; primes.print(4,verbosity);
|
|
}
|
|
|
|
lb = x[0] & ~x[2] & x[3];
|
|
primes = lb.MaximallyExpand(ub,f);
|
|
assert(primes == lb);
|
|
lprime = primes.LargestPrimeUnate(lb);
|
|
assert(lprime == primes);
|
|
if (verbosity) {
|
|
cout << "primes(3)"; primes.print(4,verbosity);
|
|
}
|
|
|
|
lb = ~x[0] & x[1] & ~x[2] & x[3];
|
|
ub = mgr.bddOne();
|
|
primes = lb.MaximallyExpand(ub,f);
|
|
assert(primes == ((x[1] & x[3]) | (~x[0] & x[1] & ~x[2])));
|
|
lprime = primes.LargestPrimeUnate(lb);
|
|
assert(lprime == (x[1] & x[3]));
|
|
if (verbosity) {
|
|
cout << "primes(4)"; primes.print(4,1); primes.PrintCover();
|
|
}
|
|
|
|
ub = ~x[0] & x[3];
|
|
primes = lb.MaximallyExpand(ub,f);
|
|
assert(primes == (~x[0] & x[1] & x[3]));
|
|
lprime = primes.LargestPrimeUnate(lb);
|
|
assert(lprime == primes);
|
|
if (verbosity) {
|
|
cout << "primes(5)"; primes.print(4,verbosity);
|
|
}
|
|
|
|
} // testBdd5
|
|
|
|
|
|
/**
|
|
@brief Test BDD interpolation.
|
|
*/
|
|
static void
|
|
testInterpolation(
|
|
Cudd& mgr,
|
|
int verbosity)
|
|
{
|
|
BDD a = mgr.bddVar(0);
|
|
BDD b = mgr.bddVar(1);
|
|
BDD c = mgr.bddVar(2);
|
|
BDD d = mgr.bddVar(3);
|
|
|
|
BDD l1 = (a | d) & b & c;
|
|
BDD u1 = (~a & ~b & ~c) | ((a | b) & c);
|
|
BDD ip1 = l1.Interpolate(u1);
|
|
if (verbosity) {
|
|
cout << "l1"; l1.print(4,verbosity);
|
|
cout << "u1"; u1.print(4,verbosity);
|
|
cout << "interpolant1"; ip1.print(4,verbosity);
|
|
}
|
|
|
|
BDD l2 = (~a | ~b) & (a | c) & (b | c) & (a | ~b | ~d);
|
|
BDD u2 = (~b & ~d) | (~b & c & d) | (b & c & ~d);
|
|
BDD ip2 = l2.Interpolate(u2);
|
|
if (verbosity) {
|
|
cout << "l2"; l2.print(4,verbosity);
|
|
cout << "u2"; u2.print(4,verbosity);
|
|
cout << "interpolant2"; ip2.print(4,verbosity);
|
|
}
|
|
|
|
BDD l3 = ~a & ~b & d;
|
|
BDD u3 = ~b & d;
|
|
BDD ip3 = l3.Interpolate(u3);
|
|
if (verbosity) {
|
|
cout << "l3"; l3.print(4,verbosity);
|
|
cout << "u3"; u3.print(4,verbosity);
|
|
cout << "interpolant3"; ip3.print(4,verbosity);
|
|
}
|
|
|
|
} // testInterpolation
|
|
|
|
|
|
/**
|
|
@brief Basic test of error handling.
|
|
|
|
@details This function also illustrates the use of the overloading of the
|
|
stream insertion operator (operator<<) for BDDs.
|
|
*/
|
|
static void
|
|
testErrorHandling(
|
|
Cudd& mgr,
|
|
int verbosity)
|
|
{
|
|
// Setup.
|
|
|
|
if (verbosity) cout << "Entering testErrorHandling\n";
|
|
|
|
FILE *savefp = 0;
|
|
if (verbosity == 0) {
|
|
// Suppress error messages coming from CUDD.
|
|
savefp = mgr.ReadStderr();
|
|
#ifndef _WIN32
|
|
FILE * devnull = fopen("/dev/null", "w");
|
|
#else
|
|
FILE * devnull = fopen("NUL", "w");
|
|
#endif
|
|
if (devnull)
|
|
mgr.SetStderr(devnull);
|
|
}
|
|
|
|
size_t const N = 60;
|
|
vector<BDD> vars;
|
|
vars.reserve(N);
|
|
for (size_t i = 0; i < N; ++i) {
|
|
vars.push_back(mgr.bddVar((int) i));
|
|
}
|
|
|
|
// It is necessary to give names to all the BDD variables in the manager
|
|
// for the names to be used by operator<<.
|
|
for (int i = 0; i < mgr.ReadSize(); ++i) {
|
|
ostringstream os;
|
|
os << "var[" << i << "]";
|
|
mgr.pushVariableName(os.str());
|
|
}
|
|
|
|
// Tests.
|
|
|
|
// Trying to print the expression of an empty BDD.
|
|
try {
|
|
BDD empty;
|
|
if (verbosity > 0)
|
|
cout << "Oops! ";
|
|
cout << empty << endl;
|
|
} catch (logic_error const & e) {
|
|
if (verbosity > 0)
|
|
cerr << "Caught: " << e.what() << endl;
|
|
}
|
|
|
|
// Trying to extract a minterm from the zero BDD.
|
|
try {
|
|
BDD zero = mgr.bddZero();
|
|
BDD minterm = zero.PickOneMinterm(vars);
|
|
} catch (logic_error const & e) {
|
|
if (verbosity > 0)
|
|
cerr << "Caught: " << e.what() << endl;
|
|
mgr.ClearErrorCode();
|
|
}
|
|
|
|
// Passing a non-cube second argument to Cofactor.
|
|
try {
|
|
BDD f = vars.at(1) | (vars.at(2) & vars.at(3));
|
|
if (verbosity > 0)
|
|
cout << "f = " << f << endl;
|
|
BDD notAcube = vars.at(0) | vars.at(1);
|
|
if (verbosity > 0)
|
|
cout << notAcube << " is not a cube" << endl;
|
|
BDD fc = f.Cofactor(notAcube);
|
|
if (verbosity > 0) {
|
|
cout << "The cofactor is: "; fc.summary(3);
|
|
}
|
|
} catch (logic_error const & e) {
|
|
if (verbosity > 0)
|
|
cerr << "Caught: " << e.what() << endl;
|
|
mgr.ClearErrorCode();
|
|
}
|
|
|
|
#if 0
|
|
// This attempt to allocate over 100 GB may succeed on machines with
|
|
// enough memory; hence we exclude it from "make check."
|
|
// Failing malloc.
|
|
// Don't let the memory manager kill the program if malloc fails.
|
|
DD_OOMFP saveHandler = mgr.InstallOutOfMemoryHandler(Cudd_OutOfMemSilent);
|
|
try {
|
|
mgr.Reserve(2000000000);
|
|
} catch (logic_error const & e) {
|
|
if (verbosity > 0)
|
|
cerr << "Caught: " << e.what() << endl;
|
|
mgr.ClearErrorCode();
|
|
}
|
|
(void) mgr.InstallOutOfMemoryHandler(saveHandler);
|
|
#endif
|
|
|
|
// Forgetting to check for empty result when setting a limit on
|
|
// the number of new nodes.
|
|
try {
|
|
BDD f = mgr.bddOne();
|
|
BDD g = f;
|
|
for (size_t i = 0; i < N/2; i += 4) {
|
|
f &= vars.at(i) | vars.at(i+N/2);
|
|
g &= vars.at(i+1) | vars.at(i+N/2+1);
|
|
}
|
|
if (verbosity > 0) {
|
|
cout << "f "; f.summary(N);
|
|
cout << "g "; g.summary(N);
|
|
}
|
|
BDD h = f.And(g, /* max new nodes */ 1);
|
|
if (verbosity > 0) {
|
|
cout << "h "; h.summary(N);
|
|
}
|
|
} catch (logic_error const & e) {
|
|
if (verbosity > 0)
|
|
cerr << "Caught: " << e.what() << endl;
|
|
mgr.ClearErrorCode();
|
|
}
|
|
|
|
// Using more memory than the set limit.
|
|
size_t saveLimit = mgr.SetMaxMemory((size_t) 1);
|
|
try {
|
|
// The limit is ridiculously low (1 byte), but CUDD is resourceful.
|
|
// Therefore we can still create a few BDDs.
|
|
BDD f = mgr.Interval(vars, 122346345U, 348353453U);
|
|
if (verbosity > 0) {
|
|
cout << "f "; f.summary(N);
|
|
}
|
|
BDD g = mgr.Interval(vars, 34234U, 3143534534U);
|
|
if (verbosity > 0) {
|
|
cout << "g "; g.summary(N);
|
|
}
|
|
BDD h = f ^ g;
|
|
if (verbosity > 0) {
|
|
cout << "h "; h.summary(N);
|
|
}
|
|
// But if we really insist...
|
|
BDD extra = mgr.bddVar(60000);
|
|
// Here we would have to fix the variable names.
|
|
} catch (logic_error const & e) {
|
|
if (verbosity > 0)
|
|
cerr << "Caught: " << e.what() << endl;
|
|
mgr.ClearErrorCode();
|
|
}
|
|
(void) mgr.SetMaxMemory(saveLimit);
|
|
|
|
// Timing out.
|
|
unsigned long saveTl = mgr.SetTimeLimit(1UL); // 1 ms
|
|
try {
|
|
BDD f = mgr.bddOne();
|
|
for (size_t i = 0; i < N/2; ++i) {
|
|
f &= vars.at(i) | vars.at(i+N/2);
|
|
}
|
|
} catch (logic_error const & e) {
|
|
if (verbosity > 0)
|
|
cerr << "Caught: " << e.what() << endl;
|
|
mgr.ClearErrorCode();
|
|
}
|
|
(void) mgr.SetTimeLimit(saveTl);
|
|
|
|
// Let's clean up after ourselves.
|
|
mgr.clearVariableNames();
|
|
if (verbosity == 0) {
|
|
mgr.SetStderr(savefp);
|
|
}
|
|
|
|
} // testErrorHandling
|