summaryrefslogtreecommitdiffstats
path: root/src/bdd
diff options
context:
space:
mode:
authorAlan Mishchenko <alanmi@berkeley.edu>2005-07-29 08:01:00 -0700
committerAlan Mishchenko <alanmi@berkeley.edu>2005-07-29 08:01:00 -0700
commit888e5bed5d7f56a5d86d91a6e8e88f3e5a3454dc (patch)
tree11d48c9e9069f54dc300c3571ae63c744c802c50 /src/bdd
parent7f94414388cce67bd3cc1a6d6269f0ed31ed0d06 (diff)
downloadabc-888e5bed5d7f56a5d86d91a6e8e88f3e5a3454dc.tar.gz
abc-888e5bed5d7f56a5d86d91a6e8e88f3e5a3454dc.tar.bz2
abc-888e5bed5d7f56a5d86d91a6e8e88f3e5a3454dc.zip
Version abc50729
Diffstat (limited to 'src/bdd')
-rw-r--r--src/bdd/cudd/cuBdd.make41
-rw-r--r--src/bdd/cudd/cudd.h959
-rw-r--r--src/bdd/cudd/cudd.make42
-rw-r--r--src/bdd/cudd/cuddAPI.c4409
-rw-r--r--src/bdd/cudd/cuddAddAbs.c566
-rw-r--r--src/bdd/cudd/cuddAddApply.c917
-rw-r--r--src/bdd/cudd/cuddAddFind.c283
-rw-r--r--src/bdd/cudd/cuddAddInv.c172
-rw-r--r--src/bdd/cudd/cuddAddIte.c613
-rw-r--r--src/bdd/cudd/cuddAddNeg.c262
-rw-r--r--src/bdd/cudd/cuddAddWalsh.c364
-rw-r--r--src/bdd/cudd/cuddAndAbs.c306
-rw-r--r--src/bdd/cudd/cuddAnneal.c788
-rw-r--r--src/bdd/cudd/cuddApa.c930
-rw-r--r--src/bdd/cudd/cuddApprox.c2192
-rw-r--r--src/bdd/cudd/cuddBddAbs.c689
-rw-r--r--src/bdd/cudd/cuddBddCorr.c481
-rw-r--r--src/bdd/cudd/cuddBddIte.c1254
-rw-r--r--src/bdd/cudd/cuddBridge.c981
-rw-r--r--src/bdd/cudd/cuddCache.c1023
-rw-r--r--src/bdd/cudd/cuddCheck.c851
-rw-r--r--src/bdd/cudd/cuddClip.c531
-rw-r--r--src/bdd/cudd/cuddCof.c300
-rw-r--r--src/bdd/cudd/cuddCompose.c1722
-rw-r--r--src/bdd/cudd/cuddDecomp.c2150
-rw-r--r--src/bdd/cudd/cuddEssent.c279
-rw-r--r--src/bdd/cudd/cuddExact.c1004
-rw-r--r--src/bdd/cudd/cuddExport.c1289
-rw-r--r--src/bdd/cudd/cuddGenCof.c1968
-rw-r--r--src/bdd/cudd/cuddGenetic.c921
-rw-r--r--src/bdd/cudd/cuddGroup.c2142
-rw-r--r--src/bdd/cudd/cuddHarwell.c541
-rw-r--r--src/bdd/cudd/cuddInit.c283
-rw-r--r--src/bdd/cudd/cuddInt.h1133
-rw-r--r--src/bdd/cudd/cuddInteract.c402
-rw-r--r--src/bdd/cudd/cuddLCache.c1428
-rw-r--r--src/bdd/cudd/cuddLevelQ.c533
-rw-r--r--src/bdd/cudd/cuddLinear.c1333
-rw-r--r--src/bdd/cudd/cuddLiteral.c237
-rw-r--r--src/bdd/cudd/cuddMatMult.c680
-rw-r--r--src/bdd/cudd/cuddPriority.c1475
-rw-r--r--src/bdd/cudd/cuddRead.c490
-rw-r--r--src/bdd/cudd/cuddRef.c781
-rw-r--r--src/bdd/cudd/cuddReorder.c2090
-rw-r--r--src/bdd/cudd/cuddSat.c1305
-rw-r--r--src/bdd/cudd/cuddSign.c292
-rw-r--r--src/bdd/cudd/cuddSolve.c339
-rw-r--r--src/bdd/cudd/cuddSplit.c657
-rw-r--r--src/bdd/cudd/cuddSubsetHB.c1311
-rw-r--r--src/bdd/cudd/cuddSubsetSP.c1624
-rw-r--r--src/bdd/cudd/cuddSymmetry.c1668
-rw-r--r--src/bdd/cudd/cuddTable.c3141
-rw-r--r--src/bdd/cudd/cuddUtil.c3633
-rw-r--r--src/bdd/cudd/cuddWindow.c997
-rw-r--r--src/bdd/cudd/cuddZddCount.c324
-rw-r--r--src/bdd/cudd/cuddZddFuncs.c1603
-rw-r--r--src/bdd/cudd/cuddZddGroup.c1317
-rw-r--r--src/bdd/cudd/cuddZddIsop.c885
-rw-r--r--src/bdd/cudd/cuddZddLin.c939
-rw-r--r--src/bdd/cudd/cuddZddMisc.c252
-rw-r--r--src/bdd/cudd/cuddZddPort.c354
-rw-r--r--src/bdd/cudd/cuddZddReord.c1633
-rw-r--r--src/bdd/cudd/cuddZddSetop.c1137
-rw-r--r--src/bdd/cudd/cuddZddSymm.c1677
-rw-r--r--src/bdd/cudd/cuddZddUtil.c1021
-rw-r--r--src/bdd/cudd/module.make61
-rw-r--r--src/bdd/cudd/r7x8.1.mat53
-rw-r--r--src/bdd/cudd/testcudd.c988
-rw-r--r--src/bdd/dsd/dsd.h115
-rw-r--r--src/bdd/dsd/dsdApi.c95
-rw-r--r--src/bdd/dsd/dsdCheck.c314
-rw-r--r--src/bdd/dsd/dsdInt.h88
-rw-r--r--src/bdd/dsd/dsdLocal.c337
-rw-r--r--src/bdd/dsd/dsdMan.c113
-rw-r--r--src/bdd/dsd/dsdProc.c1607
-rw-r--r--src/bdd/dsd/dsdTree.c838
-rw-r--r--src/bdd/dsd/module.make6
-rw-r--r--src/bdd/epd/epd.c1314
-rw-r--r--src/bdd/epd/epd.h160
-rw-r--r--src/bdd/epd/module.make1
-rw-r--r--src/bdd/mtr/module.make2
-rw-r--r--src/bdd/mtr/mtr.h173
-rw-r--r--src/bdd/mtr/mtrBasic.c426
-rw-r--r--src/bdd/mtr/mtrGroup.c690
-rw-r--r--src/bdd/mtr/mtrInt.h65
-rw-r--r--src/bdd/parse/module.make2
-rw-r--r--src/bdd/parse/parse.h53
-rw-r--r--src/bdd/parse/parseCore.c504
-rw-r--r--src/bdd/parse/parseInt.h73
-rw-r--r--src/bdd/parse/parseStack.c243
-rw-r--r--src/bdd/reo/module.make7
-rw-r--r--src/bdd/reo/reo.h222
-rw-r--r--src/bdd/reo/reoApi.c289
-rw-r--r--src/bdd/reo/reoCore.c438
-rw-r--r--src/bdd/reo/reoProfile.c365
-rw-r--r--src/bdd/reo/reoSift.c341
-rw-r--r--src/bdd/reo/reoSwap.c898
-rw-r--r--src/bdd/reo/reoTest.c251
-rw-r--r--src/bdd/reo/reoTransfer.c199
-rw-r--r--src/bdd/reo/reoUnits.c184
100 files changed, 79459 insertions, 0 deletions
diff --git a/src/bdd/cudd/cuBdd.make b/src/bdd/cudd/cuBdd.make
new file mode 100644
index 00000000..b16a27b3
--- /dev/null
+++ b/src/bdd/cudd/cuBdd.make
@@ -0,0 +1,41 @@
+CSRC_cu += cuddAPI.c cuddAddAbs.c cuddAddApply.c cuddAddFind.c cuddAddIte.c \
+ cuddAddInv.c cuddAddNeg.c cuddAddWalsh.c cuddAndAbs.c \
+ cuddAnneal.c cuddApa.c cuddApprox.c cuddBddAbs.c cuddBddCorr.c \
+ cuddBddIte.c cuddBridge.c cuddCache.c cuddCheck.c cuddClip.c \
+ cuddCof.c cuddCompose.c cuddDecomp.c cuddEssent.c cuddExact.c \
+ cuddExport.c cuddGenCof.c cuddGenetic.c \
+ cuddGroup.c cuddHarwell.c cuddInit.c cuddInteract.c \
+ cuddLCache.c cuddLevelQ.c \
+ cuddLinear.c cuddLiteral.c cuddMatMult.c cuddPriority.c \
+ cuddRead.c cuddRef.c cuddReorder.c cuddSat.c cuddSign.c \
+ cuddSolve.c cuddSplit.c cuddSubsetHB.c cuddSubsetSP.c cuddSymmetry.c \
+ cuddTable.c cuddUtil.c cuddWindow.c cuddZddCount.c cuddZddFuncs.c \
+ cuddZddGroup.c cuddZddIsop.c cuddZddLin.c cuddZddMisc.c cuddZddPort.c \
+ cuddZddReord.c cuddZddSetop.c cuddZddSymm.c cuddZddUtil.c
+HEADERS_cu += cudd.h cuddInt.h
+MISC += testcudd.c r7x8.1.mat doc/cudd.ps doc/cuddAllAbs.html doc/cuddAllDet.html \
+ doc/cuddExtAbs.html doc/cuddExtDet.html doc/cuddIntro.css \
+ doc/cuddIntro.html doc/footnode.html doc/img1.gif doc/img2.gif \
+ doc/img3.gif doc/img4.gif doc/img5.gif doc/index.html \
+ doc/node1.html doc/node2.html doc/node3.html doc/node4.html \
+ doc/node5.html doc/node6.html doc/node7.html doc/node8.html \
+ doc/icons/change_begin.gif \
+ doc/icons/change_delete.gif \
+ doc/icons/change_end.gif \
+ doc/icons/contents_motif.gif \
+ doc/icons/cross_ref_motif.gif \
+ doc/icons/foot_motif.gif \
+ doc/icons/image.gif \
+ doc/icons/index_motif.gif \
+ doc/icons/next_group_motif.gif \
+ doc/icons/next_group_motif_gr.gif \
+ doc/icons/next_motif.gif \
+ doc/icons/next_motif_gr.gif \
+ doc/icons/previous_group_motif.gif \
+ doc/icons/previous_group_motif_gr.gif \
+ doc/icons/previous_motif.gif \
+ doc/icons/previous_motif_gr.gif \
+ doc/icons/up_motif.gif \
+ doc/icons/up_motif_gr.gif
+
+DEPENDENCYFILES = $(CSRC_cu)
diff --git a/src/bdd/cudd/cudd.h b/src/bdd/cudd/cudd.h
new file mode 100644
index 00000000..a31fcdae
--- /dev/null
+++ b/src/bdd/cudd/cudd.h
@@ -0,0 +1,959 @@
+/**CHeaderFile*****************************************************************
+
+ FileName [cudd.h]
+
+ PackageName [cudd]
+
+ Synopsis [The University of Colorado decision diagram package.]
+
+ Description [External functions and data strucures of the CUDD package.
+ <ul>
+ <li> To turn on the gathering of statistics, define DD_STATS.
+ <li> To link with mis, define DD_MIS.
+ </ul>
+ Modified by Abelardo Pardo to interface it to VIS.
+ ]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+ Revision [$Id: cudd.h,v 1.1.1.1 2003/02/24 22:23:50 wjiang Exp $]
+
+******************************************************************************/
+
+#ifndef _CUDD
+#define _CUDD
+
+/*---------------------------------------------------------------------------*/
+/* Nested includes */
+/*---------------------------------------------------------------------------*/
+
+#include "mtr.h"
+#include "epd.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define CUDD_VERSION "2.3.1"
+
+#ifndef SIZEOF_VOID_P
+#define SIZEOF_VOID_P 4
+#endif
+#ifndef SIZEOF_INT
+#define SIZEOF_INT 4
+#endif
+#ifndef SIZEOF_LONG
+#define SIZEOF_LONG 4
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define CUDD_VALUE_TYPE double
+#define CUDD_OUT_OF_MEM -1
+/* The sizes of the subtables and the cache must be powers of two. */
+#define CUDD_UNIQUE_SLOTS 256 /* initial size of subtables */
+#define CUDD_CACHE_SLOTS 262144 /* default size of the cache */
+
+/* Constants for residue functions. */
+#define CUDD_RESIDUE_DEFAULT 0
+#define CUDD_RESIDUE_MSB 1
+#define CUDD_RESIDUE_TC 2
+
+/* CUDD_MAXINDEX is defined in such a way that on 32-bit and 64-bit
+** machines one can cast an index to (int) without generating a negative
+** number.
+*/
+#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
+#define CUDD_MAXINDEX (((DdHalfWord) ~0) >> 1)
+#else
+#define CUDD_MAXINDEX ((DdHalfWord) ~0)
+#endif
+
+/* CUDD_CONST_INDEX is the index of constant nodes. Currently this
+** is a synonim for CUDD_MAXINDEX. */
+#define CUDD_CONST_INDEX CUDD_MAXINDEX
+
+/* These constants define the digits used in the representation of
+** arbitrary precision integers. The two configurations tested use 8
+** and 16 bits for each digit. The typedefs should be in agreement
+** with these definitions.
+*/
+#define DD_APA_BITS 16
+#define DD_APA_BASE (1 << DD_APA_BITS)
+#define DD_APA_MASK (DD_APA_BASE - 1)
+#define DD_APA_HEXPRINT "%04x"
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/**Enum************************************************************************
+
+ Synopsis [Type of reordering algorithm.]
+
+ Description [Type of reordering algorithm.]
+
+******************************************************************************/
+typedef enum {
+ CUDD_REORDER_SAME,
+ CUDD_REORDER_NONE,
+ CUDD_REORDER_RANDOM,
+ CUDD_REORDER_RANDOM_PIVOT,
+ CUDD_REORDER_SIFT,
+ CUDD_REORDER_SIFT_CONVERGE,
+ CUDD_REORDER_SYMM_SIFT,
+ CUDD_REORDER_SYMM_SIFT_CONV,
+ CUDD_REORDER_WINDOW2,
+ CUDD_REORDER_WINDOW3,
+ CUDD_REORDER_WINDOW4,
+ CUDD_REORDER_WINDOW2_CONV,
+ CUDD_REORDER_WINDOW3_CONV,
+ CUDD_REORDER_WINDOW4_CONV,
+ CUDD_REORDER_GROUP_SIFT,
+ CUDD_REORDER_GROUP_SIFT_CONV,
+ CUDD_REORDER_ANNEALING,
+ CUDD_REORDER_GENETIC,
+ CUDD_REORDER_LINEAR,
+ CUDD_REORDER_LINEAR_CONVERGE,
+ CUDD_REORDER_LAZY_SIFT,
+ CUDD_REORDER_EXACT
+} Cudd_ReorderingType;
+
+
+/**Enum************************************************************************
+
+ Synopsis [Type of aggregation methods.]
+
+ Description [Type of aggregation methods.]
+
+******************************************************************************/
+typedef enum {
+ CUDD_NO_CHECK,
+ CUDD_GROUP_CHECK,
+ CUDD_GROUP_CHECK2,
+ CUDD_GROUP_CHECK3,
+ CUDD_GROUP_CHECK4,
+ CUDD_GROUP_CHECK5,
+ CUDD_GROUP_CHECK6,
+ CUDD_GROUP_CHECK7,
+ CUDD_GROUP_CHECK8,
+ CUDD_GROUP_CHECK9
+} Cudd_AggregationType;
+
+
+/**Enum************************************************************************
+
+ Synopsis [Type of hooks.]
+
+ Description [Type of hooks.]
+
+******************************************************************************/
+typedef enum {
+ CUDD_PRE_GC_HOOK,
+ CUDD_POST_GC_HOOK,
+ CUDD_PRE_REORDERING_HOOK,
+ CUDD_POST_REORDERING_HOOK
+} Cudd_HookType;
+
+
+/**Enum************************************************************************
+
+ Synopsis [Type of error codes.]
+
+ Description [Type of error codes.]
+
+******************************************************************************/
+typedef enum {
+ CUDD_NO_ERROR,
+ CUDD_MEMORY_OUT,
+ CUDD_TOO_MANY_NODES,
+ CUDD_MAX_MEM_EXCEEDED,
+ CUDD_INVALID_ARG,
+ CUDD_INTERNAL_ERROR
+} Cudd_ErrorType;
+
+
+/**Enum************************************************************************
+
+ Synopsis [Group type for lazy sifting.]
+
+ Description [Group type for lazy sifting.]
+
+******************************************************************************/
+typedef enum {
+ CUDD_LAZY_NONE,
+ CUDD_LAZY_SOFT_GROUP,
+ CUDD_LAZY_HARD_GROUP,
+ CUDD_LAZY_UNGROUP
+} Cudd_LazyGroupType;
+
+
+/**Enum************************************************************************
+
+ Synopsis [Variable type.]
+
+ Description [Variable type. Currently used only in lazy sifting.]
+
+******************************************************************************/
+typedef enum {
+ CUDD_VAR_PRIMARY_INPUT,
+ CUDD_VAR_PRESENT_STATE,
+ CUDD_VAR_NEXT_STATE
+} Cudd_VariableType;
+
+
+#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
+typedef unsigned int DdHalfWord;
+#else
+typedef unsigned short DdHalfWord;
+#endif
+
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+
+typedef struct DdNode DdNode;
+
+typedef struct DdChildren {
+ struct DdNode *T;
+ struct DdNode *E;
+} DdChildren;
+
+/* The DdNode structure is the only one exported out of the package */
+struct DdNode {
+ DdHalfWord index;
+ DdHalfWord ref; /* reference count */
+ DdNode *next; /* next pointer for unique table */
+ union {
+ CUDD_VALUE_TYPE value; /* for constant nodes */
+ DdChildren kids; /* for internal nodes */
+ } type;
+};
+
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+
+typedef struct DdManager DdManager;
+
+typedef struct DdGen DdGen;
+
+/* These typedefs for arbitrary precision arithmetic should agree with
+** the corresponding constant definitions above. */
+typedef unsigned short int DdApaDigit;
+typedef unsigned long int DdApaDoubleDigit;
+typedef DdApaDigit * DdApaNumber;
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns 1 if the node is a constant node.]
+
+ Description [Returns 1 if the node is a constant node (rather than an
+ internal node). All constant nodes have the same index
+ (CUDD_CONST_INDEX). The pointer passed to Cudd_IsConstant may be either
+ regular or complemented.]
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+#define Cudd_IsConstant(node) ((Cudd_Regular(node))->index == CUDD_CONST_INDEX)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Complements a DD.]
+
+ Description [Complements a DD by flipping the complement attribute of
+ the pointer (the least significant bit).]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_NotCond]
+
+******************************************************************************/
+#define Cudd_Not(node) ((DdNode *)((long)(node) ^ 01))
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Complements a DD if a condition is true.]
+
+ Description [Complements a DD if condition c is true; c should be
+ either 0 or 1, because it is used directly (for efficiency). If in
+ doubt on the values c may take, use "(c) ? Cudd_Not(node) : node".]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_Not]
+
+******************************************************************************/
+#define Cudd_NotCond(node,c) ((DdNode *)((long)(node) ^ (c)))
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns the regular version of a pointer.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_Complement Cudd_IsComplement]
+
+******************************************************************************/
+#define Cudd_Regular(node) ((DdNode *)((unsigned long)(node) & ~01))
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns the complemented version of a pointer.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_Regular Cudd_IsComplement]
+
+******************************************************************************/
+#define Cudd_Complement(node) ((DdNode *)((unsigned long)(node) | 01))
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns 1 if a pointer is complemented.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_Regular Cudd_Complement]
+
+******************************************************************************/
+#define Cudd_IsComplement(node) ((int) ((long) (node) & 01))
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns the then child of an internal node.]
+
+ Description [Returns the then child of an internal node. If
+ <code>node</code> is a constant node, the result is unpredictable.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_E Cudd_V]
+
+******************************************************************************/
+#define Cudd_T(node) ((Cudd_Regular(node))->type.kids.T)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns the else child of an internal node.]
+
+ Description [Returns the else child of an internal node. If
+ <code>node</code> is a constant node, the result is unpredictable.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_T Cudd_V]
+
+******************************************************************************/
+#define Cudd_E(node) ((Cudd_Regular(node))->type.kids.E)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns the value of a constant node.]
+
+ Description [Returns the value of a constant node. If
+ <code>node</code> is an internal node, the result is unpredictable.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_T Cudd_E]
+
+******************************************************************************/
+#define Cudd_V(node) ((Cudd_Regular(node))->type.value)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns the current position in the order of variable
+ index.]
+
+ Description [Returns the current position in the order of variable
+ index. This macro is obsolete and is kept for compatibility. New
+ applications should use Cudd_ReadPerm instead.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_ReadPerm]
+
+******************************************************************************/
+#define Cudd_ReadIndex(dd,index) (Cudd_ReadPerm(dd,index))
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Iterates over the cubes of a decision diagram.]
+
+ Description [Iterates over the cubes of a decision diagram f.
+ <ul>
+ <li> DdManager *manager;
+ <li> DdNode *f;
+ <li> DdGen *gen;
+ <li> int *cube;
+ <li> CUDD_VALUE_TYPE value;
+ </ul>
+ Cudd_ForeachCube allocates and frees the generator. Therefore the
+ application should not try to do that. Also, the cube is freed at the
+ end of Cudd_ForeachCube and hence is not available outside of the loop.<p>
+ CAUTION: It is assumed that dynamic reordering will not occur while
+ there are open generators. It is the user's responsibility to make sure
+ that dynamic reordering does not occur. As long as new nodes are not created
+ during generation, and dynamic reordering is not called explicitly,
+ dynamic reordering will not occur. Alternatively, it is sufficient to
+ disable dynamic reordering. It is a mistake to dispose of a diagram
+ on which generation is ongoing.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_ForeachNode Cudd_FirstCube Cudd_NextCube Cudd_GenFree
+ Cudd_IsGenEmpty Cudd_AutodynDisable]
+
+******************************************************************************/
+#define Cudd_ForeachCube(manager, f, gen, cube, value)\
+ for((gen) = Cudd_FirstCube(manager, f, &cube, &value);\
+ Cudd_IsGenEmpty(gen) ? Cudd_GenFree(gen) : TRUE;\
+ (void) Cudd_NextCube(gen, &cube, &value))
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Iterates over the nodes of a decision diagram.]
+
+ Description [Iterates over the nodes of a decision diagram f.
+ <ul>
+ <li> DdManager *manager;
+ <li> DdNode *f;
+ <li> DdGen *gen;
+ <li> DdNode *node;
+ </ul>
+ The nodes are returned in a seemingly random order.
+ Cudd_ForeachNode allocates and frees the generator. Therefore the
+ application should not try to do that.<p>
+ CAUTION: It is assumed that dynamic reordering will not occur while
+ there are open generators. It is the user's responsibility to make sure
+ that dynamic reordering does not occur. As long as new nodes are not created
+ during generation, and dynamic reordering is not called explicitly,
+ dynamic reordering will not occur. Alternatively, it is sufficient to
+ disable dynamic reordering. It is a mistake to dispose of a diagram
+ on which generation is ongoing.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_ForeachCube Cudd_FirstNode Cudd_NextNode Cudd_GenFree
+ Cudd_IsGenEmpty Cudd_AutodynDisable]
+
+******************************************************************************/
+#define Cudd_ForeachNode(manager, f, gen, node)\
+ for((gen) = Cudd_FirstNode(manager, f, &node);\
+ Cudd_IsGenEmpty(gen) ? Cudd_GenFree(gen) : TRUE;\
+ (void) Cudd_NextNode(gen, &node))
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Iterates over the paths of a ZDD.]
+
+ Description [Iterates over the paths of a ZDD f.
+ <ul>
+ <li> DdManager *manager;
+ <li> DdNode *f;
+ <li> DdGen *gen;
+ <li> int *path;
+ </ul>
+ Cudd_zddForeachPath allocates and frees the generator. Therefore the
+ application should not try to do that. Also, the path is freed at the
+ end of Cudd_zddForeachPath and hence is not available outside of the loop.<p>
+ CAUTION: It is assumed that dynamic reordering will not occur while
+ there are open generators. It is the user's responsibility to make sure
+ that dynamic reordering does not occur. As long as new nodes are not created
+ during generation, and dynamic reordering is not called explicitly,
+ dynamic reordering will not occur. Alternatively, it is sufficient to
+ disable dynamic reordering. It is a mistake to dispose of a diagram
+ on which generation is ongoing.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_zddFirstPath Cudd_zddNextPath Cudd_GenFree
+ Cudd_IsGenEmpty Cudd_AutodynDisable]
+
+******************************************************************************/
+#define Cudd_zddForeachPath(manager, f, gen, path)\
+ for((gen) = Cudd_zddFirstPath(manager, f, &path);\
+ Cudd_IsGenEmpty(gen) ? Cudd_GenFree(gen) : TRUE;\
+ (void) Cudd_zddNextPath(gen, &path))
+
+
+/* These are potential duplicates. */
+#ifndef EXTERN
+# ifdef __cplusplus
+# define EXTERN extern "C"
+# else
+# define EXTERN extern
+# endif
+#endif
+#ifndef ARGS
+# if defined(__STDC__) || defined(__cplusplus)
+# define ARGS(protos) protos /* ANSI C */
+# else /* !(__STDC__ || __cplusplus) */
+# define ARGS(protos) () /* K&R C */
+# endif /* !(__STDC__ || __cplusplus) */
+#endif
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Function prototypes */
+/*---------------------------------------------------------------------------*/
+
+EXTERN DdNode * Cudd_addNewVar ARGS((DdManager *dd));
+EXTERN DdNode * Cudd_addNewVarAtLevel ARGS((DdManager *dd, int level));
+EXTERN DdNode * Cudd_bddNewVar ARGS((DdManager *dd));
+EXTERN DdNode * Cudd_bddNewVarAtLevel ARGS((DdManager *dd, int level));
+EXTERN DdNode * Cudd_addIthVar ARGS((DdManager *dd, int i));
+EXTERN DdNode * Cudd_bddIthVar ARGS((DdManager *dd, int i));
+EXTERN DdNode * Cudd_zddIthVar ARGS((DdManager *dd, int i));
+EXTERN int Cudd_zddVarsFromBddVars ARGS((DdManager *dd, int multiplicity));
+EXTERN DdNode * Cudd_addConst ARGS((DdManager *dd, CUDD_VALUE_TYPE c));
+EXTERN int Cudd_IsNonConstant ARGS((DdNode *f));
+EXTERN void Cudd_AutodynEnable ARGS((DdManager *unique, Cudd_ReorderingType method));
+EXTERN void Cudd_AutodynDisable ARGS((DdManager *unique));
+EXTERN int Cudd_ReorderingStatus ARGS((DdManager *unique, Cudd_ReorderingType *method));
+EXTERN void Cudd_AutodynEnableZdd ARGS((DdManager *unique, Cudd_ReorderingType method));
+EXTERN void Cudd_AutodynDisableZdd ARGS((DdManager *unique));
+EXTERN int Cudd_ReorderingStatusZdd ARGS((DdManager *unique, Cudd_ReorderingType *method));
+EXTERN int Cudd_zddRealignmentEnabled ARGS((DdManager *unique));
+EXTERN void Cudd_zddRealignEnable ARGS((DdManager *unique));
+EXTERN void Cudd_zddRealignDisable ARGS((DdManager *unique));
+EXTERN int Cudd_bddRealignmentEnabled ARGS((DdManager *unique));
+EXTERN void Cudd_bddRealignEnable ARGS((DdManager *unique));
+EXTERN void Cudd_bddRealignDisable ARGS((DdManager *unique));
+EXTERN DdNode * Cudd_ReadOne ARGS((DdManager *dd));
+EXTERN DdNode * Cudd_ReadZddOne ARGS((DdManager *dd, int i));
+EXTERN DdNode * Cudd_ReadZero ARGS((DdManager *dd));
+EXTERN DdNode * Cudd_ReadLogicZero ARGS((DdManager *dd));
+EXTERN DdNode * Cudd_ReadPlusInfinity ARGS((DdManager *dd));
+EXTERN DdNode * Cudd_ReadMinusInfinity ARGS((DdManager *dd));
+EXTERN DdNode * Cudd_ReadBackground ARGS((DdManager *dd));
+EXTERN void Cudd_SetBackground ARGS((DdManager *dd, DdNode *bck));
+EXTERN unsigned int Cudd_ReadCacheSlots ARGS((DdManager *dd));
+EXTERN double Cudd_ReadCacheUsedSlots ARGS((DdManager * dd));
+EXTERN double Cudd_ReadCacheLookUps ARGS((DdManager *dd));
+EXTERN double Cudd_ReadCacheHits ARGS((DdManager *dd));
+EXTERN double Cudd_ReadRecursiveCalls ARGS ((DdManager * dd));
+EXTERN unsigned int Cudd_ReadMinHit ARGS((DdManager *dd));
+EXTERN void Cudd_SetMinHit ARGS((DdManager *dd, unsigned int hr));
+EXTERN unsigned int Cudd_ReadLooseUpTo ARGS((DdManager *dd));
+EXTERN void Cudd_SetLooseUpTo ARGS((DdManager *dd, unsigned int lut));
+EXTERN unsigned int Cudd_ReadMaxCache ARGS((DdManager *dd));
+EXTERN unsigned int Cudd_ReadMaxCacheHard ARGS((DdManager *dd));
+EXTERN void Cudd_SetMaxCacheHard ARGS((DdManager *dd, unsigned int mc));
+EXTERN int Cudd_ReadSize ARGS((DdManager *dd));
+EXTERN int Cudd_ReadZddSize ARGS((DdManager *dd));
+EXTERN unsigned int Cudd_ReadSlots ARGS((DdManager *dd));
+EXTERN double Cudd_ReadUsedSlots ARGS((DdManager * dd));
+EXTERN double Cudd_ExpectedUsedSlots ARGS((DdManager * dd));
+EXTERN unsigned int Cudd_ReadKeys ARGS((DdManager *dd));
+EXTERN unsigned int Cudd_ReadDead ARGS((DdManager *dd));
+EXTERN unsigned int Cudd_ReadMinDead ARGS((DdManager *dd));
+EXTERN int Cudd_ReadReorderings ARGS((DdManager *dd));
+EXTERN long Cudd_ReadReorderingTime ARGS((DdManager * dd));
+EXTERN int Cudd_ReadGarbageCollections ARGS((DdManager * dd));
+EXTERN long Cudd_ReadGarbageCollectionTime ARGS((DdManager * dd));
+EXTERN double Cudd_ReadNodesFreed ARGS((DdManager * dd));
+EXTERN double Cudd_ReadNodesDropped ARGS((DdManager * dd));
+EXTERN double Cudd_ReadUniqueLookUps ARGS((DdManager * dd));
+EXTERN double Cudd_ReadUniqueLinks ARGS((DdManager * dd));
+EXTERN int Cudd_ReadSiftMaxVar ARGS((DdManager *dd));
+EXTERN void Cudd_SetSiftMaxVar ARGS((DdManager *dd, int smv));
+EXTERN int Cudd_ReadSiftMaxSwap ARGS((DdManager *dd));
+EXTERN void Cudd_SetSiftMaxSwap ARGS((DdManager *dd, int sms));
+EXTERN double Cudd_ReadMaxGrowth ARGS((DdManager *dd));
+EXTERN void Cudd_SetMaxGrowth ARGS((DdManager *dd, double mg));
+EXTERN double Cudd_ReadMaxGrowthAlternate ARGS((DdManager * dd));
+EXTERN void Cudd_SetMaxGrowthAlternate ARGS((DdManager * dd, double mg));
+EXTERN int Cudd_ReadReorderingCycle ARGS((DdManager * dd));
+EXTERN void Cudd_SetReorderingCycle ARGS((DdManager * dd, int cycle));
+EXTERN MtrNode * Cudd_ReadTree ARGS((DdManager *dd));
+EXTERN void Cudd_SetTree ARGS((DdManager *dd, MtrNode *tree));
+EXTERN void Cudd_FreeTree ARGS((DdManager *dd));
+EXTERN MtrNode * Cudd_ReadZddTree ARGS((DdManager *dd));
+EXTERN void Cudd_SetZddTree ARGS((DdManager *dd, MtrNode *tree));
+EXTERN void Cudd_FreeZddTree ARGS((DdManager *dd));
+EXTERN unsigned int Cudd_NodeReadIndex ARGS((DdNode *node));
+EXTERN int Cudd_ReadPerm ARGS((DdManager *dd, int i));
+EXTERN int Cudd_ReadPermZdd ARGS((DdManager *dd, int i));
+EXTERN int Cudd_ReadInvPerm ARGS((DdManager *dd, int i));
+EXTERN int Cudd_ReadInvPermZdd ARGS((DdManager *dd, int i));
+EXTERN DdNode * Cudd_ReadVars ARGS((DdManager *dd, int i));
+EXTERN CUDD_VALUE_TYPE Cudd_ReadEpsilon ARGS((DdManager *dd));
+EXTERN void Cudd_SetEpsilon ARGS((DdManager *dd, CUDD_VALUE_TYPE ep));
+EXTERN Cudd_AggregationType Cudd_ReadGroupcheck ARGS((DdManager *dd));
+EXTERN void Cudd_SetGroupcheck ARGS((DdManager *dd, Cudd_AggregationType gc));
+EXTERN int Cudd_GarbageCollectionEnabled ARGS((DdManager *dd));
+EXTERN void Cudd_EnableGarbageCollection ARGS((DdManager *dd));
+EXTERN void Cudd_DisableGarbageCollection ARGS((DdManager *dd));
+EXTERN int Cudd_DeadAreCounted ARGS((DdManager *dd));
+EXTERN void Cudd_TurnOnCountDead ARGS((DdManager *dd));
+EXTERN void Cudd_TurnOffCountDead ARGS((DdManager *dd));
+EXTERN int Cudd_ReadRecomb ARGS((DdManager *dd));
+EXTERN void Cudd_SetRecomb ARGS((DdManager *dd, int recomb));
+EXTERN int Cudd_ReadSymmviolation ARGS((DdManager *dd));
+EXTERN void Cudd_SetSymmviolation ARGS((DdManager *dd, int symmviolation));
+EXTERN int Cudd_ReadArcviolation ARGS((DdManager *dd));
+EXTERN void Cudd_SetArcviolation ARGS((DdManager *dd, int arcviolation));
+EXTERN int Cudd_ReadPopulationSize ARGS((DdManager *dd));
+EXTERN void Cudd_SetPopulationSize ARGS((DdManager *dd, int populationSize));
+EXTERN int Cudd_ReadNumberXovers ARGS((DdManager *dd));
+EXTERN void Cudd_SetNumberXovers ARGS((DdManager *dd, int numberXovers));
+EXTERN long Cudd_ReadMemoryInUse ARGS((DdManager *dd));
+EXTERN int Cudd_PrintInfo ARGS((DdManager *dd, FILE *fp));
+EXTERN long Cudd_ReadPeakNodeCount ARGS((DdManager *dd));
+EXTERN int Cudd_ReadPeakLiveNodeCount ARGS((DdManager * dd));
+EXTERN long Cudd_ReadNodeCount ARGS((DdManager *dd));
+EXTERN long Cudd_zddReadNodeCount ARGS((DdManager *dd));
+EXTERN int Cudd_AddHook ARGS((DdManager *dd, int (*f)(DdManager *, char *, void *), Cudd_HookType where));
+EXTERN int Cudd_RemoveHook ARGS((DdManager *dd, int (*f)(DdManager *, char *, void *), Cudd_HookType where));
+EXTERN int Cudd_IsInHook ARGS((DdManager * dd, int (*f)(DdManager *, char *, void *), Cudd_HookType where));
+EXTERN int Cudd_StdPreReordHook ARGS((DdManager *dd, char *str, void *data));
+EXTERN int Cudd_StdPostReordHook ARGS((DdManager *dd, char *str, void *data));
+EXTERN int Cudd_EnableReorderingReporting ARGS((DdManager *dd));
+EXTERN int Cudd_DisableReorderingReporting ARGS((DdManager *dd));
+EXTERN int Cudd_ReorderingReporting ARGS((DdManager *dd));
+EXTERN Cudd_ErrorType Cudd_ReadErrorCode ARGS((DdManager *dd));
+EXTERN void Cudd_ClearErrorCode ARGS((DdManager *dd));
+EXTERN FILE * Cudd_ReadStdout ARGS((DdManager *dd));
+EXTERN void Cudd_SetStdout ARGS((DdManager *dd, FILE *fp));
+EXTERN FILE * Cudd_ReadStderr ARGS((DdManager *dd));
+EXTERN void Cudd_SetStderr ARGS((DdManager *dd, FILE *fp));
+EXTERN unsigned int Cudd_ReadNextReordering ARGS((DdManager *dd));
+EXTERN void Cudd_SetNextReordering ARGS((DdManager *dd, unsigned int next));
+EXTERN double Cudd_ReadSwapSteps ARGS((DdManager *dd));
+EXTERN unsigned int Cudd_ReadMaxLive ARGS((DdManager *dd));
+EXTERN void Cudd_SetMaxLive ARGS((DdManager *dd, unsigned int maxLive));
+EXTERN long Cudd_ReadMaxMemory ARGS((DdManager *dd));
+EXTERN void Cudd_SetMaxMemory ARGS((DdManager *dd, long maxMemory));
+EXTERN int Cudd_bddBindVar ARGS((DdManager *dd, int index));
+EXTERN int Cudd_bddUnbindVar ARGS((DdManager *dd, int index));
+EXTERN int Cudd_bddVarIsBound ARGS((DdManager *dd, int index));
+EXTERN DdNode * Cudd_addExistAbstract ARGS((DdManager *manager, DdNode *f, DdNode *cube));
+EXTERN DdNode * Cudd_addUnivAbstract ARGS((DdManager *manager, DdNode *f, DdNode *cube));
+EXTERN DdNode * Cudd_addOrAbstract ARGS((DdManager *manager, DdNode *f, DdNode *cube));
+EXTERN DdNode * Cudd_addApply ARGS((DdManager *dd, DdNode * (*)(DdManager *, DdNode **, DdNode **), DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_addPlus ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addTimes ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addThreshold ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addSetNZ ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addDivide ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addMinus ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addMinimum ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addMaximum ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addOneZeroMaximum ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addDiff ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addAgreement ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addOr ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addNand ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addNor ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addXor ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addXnor ARGS((DdManager *dd, DdNode **f, DdNode **g));
+EXTERN DdNode * Cudd_addMonadicApply ARGS((DdManager * dd, DdNode * (*op)(DdManager *, DdNode *), DdNode * f));
+EXTERN DdNode * Cudd_addLog ARGS((DdManager * dd, DdNode * f));
+EXTERN DdNode * Cudd_addFindMax ARGS((DdManager *dd, DdNode *f));
+EXTERN DdNode * Cudd_addFindMin ARGS((DdManager *dd, DdNode *f));
+EXTERN DdNode * Cudd_addIthBit ARGS((DdManager *dd, DdNode *f, int bit));
+EXTERN DdNode * Cudd_addScalarInverse ARGS((DdManager *dd, DdNode *f, DdNode *epsilon));
+EXTERN DdNode * Cudd_addIte ARGS((DdManager *dd, DdNode *f, DdNode *g, DdNode *h));
+EXTERN DdNode * Cudd_addIteConstant ARGS((DdManager *dd, DdNode *f, DdNode *g, DdNode *h));
+EXTERN DdNode * Cudd_addEvalConst ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN int Cudd_addLeq ARGS((DdManager * dd, DdNode * f, DdNode * g));
+EXTERN DdNode * Cudd_addCmpl ARGS((DdManager *dd, DdNode *f));
+EXTERN DdNode * Cudd_addNegate ARGS((DdManager *dd, DdNode *f));
+EXTERN DdNode * Cudd_addRoundOff ARGS((DdManager *dd, DdNode *f, int N));
+EXTERN DdNode * Cudd_addWalsh ARGS((DdManager *dd, DdNode **x, DdNode **y, int n));
+EXTERN DdNode * Cudd_addResidue ARGS((DdManager *dd, int n, int m, int options, int top));
+EXTERN DdNode * Cudd_bddAndAbstract ARGS((DdManager *manager, DdNode *f, DdNode *g, DdNode *cube));
+EXTERN int Cudd_ApaNumberOfDigits ARGS((int binaryDigits));
+EXTERN DdApaNumber Cudd_NewApaNumber ARGS((int digits));
+EXTERN void Cudd_ApaCopy ARGS((int digits, DdApaNumber source, DdApaNumber dest));
+EXTERN DdApaDigit Cudd_ApaAdd ARGS((int digits, DdApaNumber a, DdApaNumber b, DdApaNumber sum));
+EXTERN DdApaDigit Cudd_ApaSubtract ARGS((int digits, DdApaNumber a, DdApaNumber b, DdApaNumber diff));
+EXTERN DdApaDigit Cudd_ApaShortDivision ARGS((int digits, DdApaNumber dividend, DdApaDigit divisor, DdApaNumber quotient));
+EXTERN unsigned int Cudd_ApaIntDivision ARGS((int digits, DdApaNumber dividend, unsigned int divisor, DdApaNumber quotient));
+EXTERN void Cudd_ApaShiftRight ARGS((int digits, DdApaDigit in, DdApaNumber a, DdApaNumber b));
+EXTERN void Cudd_ApaSetToLiteral ARGS((int digits, DdApaNumber number, DdApaDigit literal));
+EXTERN void Cudd_ApaPowerOfTwo ARGS((int digits, DdApaNumber number, int power));
+EXTERN int Cudd_ApaCompare ARGS((int digitsFirst, DdApaNumber first, int digitsSecond, DdApaNumber second));
+EXTERN int Cudd_ApaCompareRatios ARGS ((int digitsFirst, DdApaNumber firstNum, unsigned int firstDen, int digitsSecond, DdApaNumber secondNum, unsigned int secondDen));
+EXTERN int Cudd_ApaPrintHex ARGS((FILE *fp, int digits, DdApaNumber number));
+EXTERN int Cudd_ApaPrintDecimal ARGS((FILE *fp, int digits, DdApaNumber number));
+EXTERN int Cudd_ApaPrintExponential ARGS((FILE * fp, int digits, DdApaNumber number, int precision));
+EXTERN DdApaNumber Cudd_ApaCountMinterm ARGS((DdManager *manager, DdNode *node, int nvars, int *digits));
+EXTERN int Cudd_ApaPrintMinterm ARGS((FILE *fp, DdManager *dd, DdNode *node, int nvars));
+EXTERN int Cudd_ApaPrintMintermExp ARGS((FILE * fp, DdManager * dd, DdNode * node, int nvars, int precision));
+EXTERN int Cudd_ApaPrintDensity ARGS((FILE * fp, DdManager * dd, DdNode * node, int nvars));
+EXTERN DdNode * Cudd_UnderApprox ARGS((DdManager *dd, DdNode *f, int numVars, int threshold, int safe, double quality));
+EXTERN DdNode * Cudd_OverApprox ARGS((DdManager *dd, DdNode *f, int numVars, int threshold, int safe, double quality));
+EXTERN DdNode * Cudd_RemapUnderApprox ARGS((DdManager *dd, DdNode *f, int numVars, int threshold, double quality));
+EXTERN DdNode * Cudd_RemapOverApprox ARGS((DdManager *dd, DdNode *f, int numVars, int threshold, double quality));
+EXTERN DdNode * Cudd_BiasedUnderApprox ARGS((DdManager *dd, DdNode *f, DdNode *b, int numVars, int threshold, double quality1, double quality0));
+EXTERN DdNode * Cudd_BiasedOverApprox ARGS((DdManager *dd, DdNode *f, DdNode *b, int numVars, int threshold, double quality1, double quality0));
+EXTERN DdNode * Cudd_bddExistAbstract ARGS((DdManager *manager, DdNode *f, DdNode *cube));
+EXTERN DdNode * Cudd_bddXorExistAbstract ARGS((DdManager *manager, DdNode *f, DdNode *g, DdNode *cube));
+EXTERN DdNode * Cudd_bddUnivAbstract ARGS((DdManager *manager, DdNode *f, DdNode *cube));
+EXTERN DdNode * Cudd_bddBooleanDiff ARGS((DdManager *manager, DdNode *f, int x));
+EXTERN int Cudd_bddVarIsDependent ARGS((DdManager *dd, DdNode *f, DdNode *var));
+EXTERN double Cudd_bddCorrelation ARGS((DdManager *manager, DdNode *f, DdNode *g));
+EXTERN double Cudd_bddCorrelationWeights ARGS((DdManager *manager, DdNode *f, DdNode *g, double *prob));
+EXTERN DdNode * Cudd_bddIte ARGS((DdManager *dd, DdNode *f, DdNode *g, DdNode *h));
+EXTERN DdNode * Cudd_bddIteConstant ARGS((DdManager *dd, DdNode *f, DdNode *g, DdNode *h));
+EXTERN DdNode * Cudd_bddIntersect ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_bddAnd ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_bddOr ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_bddNand ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_bddNor ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_bddXor ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_bddXnor ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN int Cudd_bddLeq ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_addBddThreshold ARGS((DdManager *dd, DdNode *f, CUDD_VALUE_TYPE value));
+EXTERN DdNode * Cudd_addBddStrictThreshold ARGS((DdManager *dd, DdNode *f, CUDD_VALUE_TYPE value));
+EXTERN DdNode * Cudd_addBddInterval ARGS((DdManager *dd, DdNode *f, CUDD_VALUE_TYPE lower, CUDD_VALUE_TYPE upper));
+EXTERN DdNode * Cudd_addBddIthBit ARGS((DdManager *dd, DdNode *f, int bit));
+EXTERN DdNode * Cudd_BddToAdd ARGS((DdManager *dd, DdNode *B));
+EXTERN DdNode * Cudd_addBddPattern ARGS((DdManager *dd, DdNode *f));
+EXTERN DdNode * Cudd_bddTransfer ARGS((DdManager *ddSource, DdManager *ddDestination, DdNode *f));
+EXTERN int Cudd_DebugCheck ARGS((DdManager *table));
+EXTERN int Cudd_CheckKeys ARGS((DdManager *table));
+EXTERN DdNode * Cudd_bddClippingAnd ARGS((DdManager *dd, DdNode *f, DdNode *g, int maxDepth, int direction));
+EXTERN DdNode * Cudd_bddClippingAndAbstract ARGS((DdManager *dd, DdNode *f, DdNode *g, DdNode *cube, int maxDepth, int direction));
+EXTERN DdNode * Cudd_Cofactor ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_bddCompose ARGS((DdManager *dd, DdNode *f, DdNode *g, int v));
+EXTERN DdNode * Cudd_addCompose ARGS((DdManager *dd, DdNode *f, DdNode *g, int v));
+EXTERN DdNode * Cudd_addPermute ARGS((DdManager *manager, DdNode *node, int *permut));
+EXTERN DdNode * Cudd_addSwapVariables ARGS((DdManager *dd, DdNode *f, DdNode **x, DdNode **y, int n));
+EXTERN DdNode * Cudd_bddPermute ARGS((DdManager *manager, DdNode *node, int *permut));
+EXTERN DdNode * Cudd_bddVarMap ARGS((DdManager *manager, DdNode *f));
+EXTERN int Cudd_SetVarMap ARGS((DdManager *manager, DdNode **x, DdNode **y, int n));
+EXTERN DdNode * Cudd_bddSwapVariables ARGS((DdManager *dd, DdNode *f, DdNode **x, DdNode **y, int n));
+EXTERN DdNode * Cudd_bddAdjPermuteX ARGS((DdManager *dd, DdNode *B, DdNode **x, int n));
+EXTERN DdNode * Cudd_addVectorCompose ARGS((DdManager *dd, DdNode *f, DdNode **vector));
+EXTERN DdNode * Cudd_addGeneralVectorCompose ARGS((DdManager *dd, DdNode *f, DdNode **vectorOn, DdNode **vectorOff));
+EXTERN DdNode * Cudd_addNonSimCompose ARGS((DdManager *dd, DdNode *f, DdNode **vector));
+EXTERN DdNode * Cudd_bddVectorCompose ARGS((DdManager *dd, DdNode *f, DdNode **vector));
+EXTERN int Cudd_bddApproxConjDecomp ARGS((DdManager *dd, DdNode *f, DdNode ***conjuncts));
+EXTERN int Cudd_bddApproxDisjDecomp ARGS((DdManager *dd, DdNode *f, DdNode ***disjuncts));
+EXTERN int Cudd_bddIterConjDecomp ARGS((DdManager *dd, DdNode *f, DdNode ***conjuncts));
+EXTERN int Cudd_bddIterDisjDecomp ARGS((DdManager *dd, DdNode *f, DdNode ***disjuncts));
+EXTERN int Cudd_bddGenConjDecomp ARGS((DdManager *dd, DdNode *f, DdNode ***conjuncts));
+EXTERN int Cudd_bddGenDisjDecomp ARGS((DdManager *dd, DdNode *f, DdNode ***disjuncts));
+EXTERN int Cudd_bddVarConjDecomp ARGS((DdManager *dd, DdNode * f, DdNode ***conjuncts));
+EXTERN int Cudd_bddVarDisjDecomp ARGS((DdManager *dd, DdNode * f, DdNode ***disjuncts));
+EXTERN DdNode * Cudd_FindEssential ARGS((DdManager *dd, DdNode *f));
+EXTERN int Cudd_bddIsVarEssential ARGS((DdManager *manager, DdNode *f, int id, int phase));
+EXTERN int Cudd_DumpBlif ARGS((DdManager *dd, int n, DdNode **f, char **inames, char **onames, char *mname, FILE *fp));
+EXTERN int Cudd_DumpBlifBody ARGS((DdManager *dd, int n, DdNode **f, char **inames, char **onames, FILE *fp));
+EXTERN int Cudd_DumpDot ARGS((DdManager *dd, int n, DdNode **f, char **inames, char **onames, FILE *fp));
+EXTERN int Cudd_DumpDaVinci ARGS((DdManager *dd, int n, DdNode **f, char **inames, char **onames, FILE *fp));
+EXTERN int Cudd_DumpDDcal ARGS((DdManager *dd, int n, DdNode **f, char **inames, char **onames, FILE *fp));
+EXTERN int Cudd_DumpFactoredForm ARGS((DdManager *dd, int n, DdNode **f, char **inames, char **onames, FILE *fp));
+EXTERN DdNode * Cudd_bddConstrain ARGS((DdManager *dd, DdNode *f, DdNode *c));
+EXTERN DdNode * Cudd_bddRestrict ARGS((DdManager *dd, DdNode *f, DdNode *c));
+EXTERN DdNode * Cudd_addConstrain ARGS((DdManager *dd, DdNode *f, DdNode *c));
+EXTERN DdNode ** Cudd_bddConstrainDecomp ARGS((DdManager *dd, DdNode *f));
+EXTERN DdNode * Cudd_addRestrict ARGS((DdManager *dd, DdNode *f, DdNode *c));
+EXTERN DdNode ** Cudd_bddCharToVect ARGS((DdManager *dd, DdNode *f));
+EXTERN DdNode * Cudd_bddLICompaction ARGS((DdManager *dd, DdNode *f, DdNode *c));
+EXTERN DdNode * Cudd_bddSqueeze ARGS((DdManager *dd, DdNode *l, DdNode *u));
+EXTERN DdNode * Cudd_bddMinimize ARGS((DdManager *dd, DdNode *f, DdNode *c));
+EXTERN DdNode * Cudd_SubsetCompress ARGS((DdManager *dd, DdNode *f, int nvars, int threshold));
+EXTERN DdNode * Cudd_SupersetCompress ARGS((DdManager *dd, DdNode *f, int nvars, int threshold));
+EXTERN MtrNode * Cudd_MakeTreeNode ARGS((DdManager *dd, unsigned int low, unsigned int size, unsigned int type));
+EXTERN int Cudd_addHarwell ARGS((FILE *fp, DdManager *dd, DdNode **E, DdNode ***x, DdNode ***y, DdNode ***xn, DdNode ***yn_, int *nx, int *ny, int *m, int *n, int bx, int sx, int by, int sy, int pr));
+EXTERN DdManager * Cudd_Init ARGS((unsigned int numVars, unsigned int numVarsZ, unsigned int numSlots, unsigned int cacheSize, unsigned long maxMemory));
+EXTERN void Cudd_Quit ARGS((DdManager *unique));
+EXTERN int Cudd_PrintLinear ARGS((DdManager *table));
+EXTERN int Cudd_ReadLinear ARGS((DdManager *table, int x, int y));
+EXTERN DdNode * Cudd_bddLiteralSetIntersection ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_addMatrixMultiply ARGS((DdManager *dd, DdNode *A, DdNode *B, DdNode **z, int nz));
+EXTERN DdNode * Cudd_addTimesPlus ARGS((DdManager *dd, DdNode *A, DdNode *B, DdNode **z, int nz));
+EXTERN DdNode * Cudd_addTriangle ARGS((DdManager *dd, DdNode *f, DdNode *g, DdNode **z, int nz));
+EXTERN DdNode * Cudd_addOuterSum ARGS((DdManager *dd, DdNode *M, DdNode *r, DdNode *c));
+EXTERN DdNode * Cudd_PrioritySelect ARGS((DdManager *dd, DdNode *R, DdNode **x, DdNode **y, DdNode **z, DdNode *Pi, int n, DdNode * (*)(DdManager *, int, DdNode **, DdNode **, DdNode **)));
+EXTERN DdNode * Cudd_Xgty ARGS((DdManager *dd, int N, DdNode **z, DdNode **x, DdNode **y));
+EXTERN DdNode * Cudd_Xeqy ARGS((DdManager *dd, int N, DdNode **x, DdNode **y));
+EXTERN DdNode * Cudd_addXeqy ARGS((DdManager *dd, int N, DdNode **x, DdNode **y));
+EXTERN DdNode * Cudd_Dxygtdxz ARGS((DdManager *dd, int N, DdNode **x, DdNode **y, DdNode **z));
+EXTERN DdNode * Cudd_Dxygtdyz ARGS((DdManager *dd, int N, DdNode **x, DdNode **y, DdNode **z));
+EXTERN DdNode * Cudd_CProjection ARGS((DdManager *dd, DdNode *R, DdNode *Y));
+EXTERN DdNode * Cudd_addHamming ARGS((DdManager *dd, DdNode **xVars, DdNode **yVars, int nVars));
+EXTERN int Cudd_MinHammingDist ARGS((DdManager *dd, DdNode *f, int *minterm, int upperBound));
+EXTERN DdNode * Cudd_bddClosestCube ARGS((DdManager *dd, DdNode * f, DdNode *g, int *distance));
+EXTERN int Cudd_addRead ARGS((FILE *fp, DdManager *dd, DdNode **E, DdNode ***x, DdNode ***y, DdNode ***xn, DdNode ***yn_, int *nx, int *ny, int *m, int *n, int bx, int sx, int by, int sy));
+EXTERN int Cudd_bddRead ARGS((FILE *fp, DdManager *dd, DdNode **E, DdNode ***x, DdNode ***y, int *nx, int *ny, int *m, int *n, int bx, int sx, int by, int sy));
+EXTERN void Cudd_Ref ARGS((DdNode *n));
+EXTERN void Cudd_RecursiveDeref ARGS((DdManager *table, DdNode *n));
+EXTERN void Cudd_IterDerefBdd ARGS((DdManager *table, DdNode *n));
+EXTERN void Cudd_DelayedDerefBdd ARGS((DdManager * table, DdNode * n));
+EXTERN void Cudd_RecursiveDerefZdd ARGS((DdManager *table, DdNode *n));
+EXTERN void Cudd_Deref ARGS((DdNode *node));
+EXTERN int Cudd_CheckZeroRef ARGS((DdManager *manager));
+EXTERN int Cudd_ReduceHeap ARGS((DdManager *table, Cudd_ReorderingType heuristic, int minsize));
+EXTERN int Cudd_ShuffleHeap ARGS((DdManager *table, int *permutation));
+EXTERN DdNode * Cudd_Eval ARGS((DdManager *dd, DdNode *f, int *inputs));
+EXTERN DdNode * Cudd_ShortestPath ARGS((DdManager *manager, DdNode *f, int *weight, int *support, int *length));
+EXTERN DdNode * Cudd_LargestCube ARGS((DdManager *manager, DdNode *f, int *length));
+EXTERN int Cudd_ShortestLength ARGS((DdManager *manager, DdNode *f, int *weight));
+EXTERN DdNode * Cudd_Decreasing ARGS((DdManager *dd, DdNode *f, int i));
+EXTERN DdNode * Cudd_Increasing ARGS((DdManager *dd, DdNode *f, int i));
+EXTERN int Cudd_EquivDC ARGS((DdManager *dd, DdNode *F, DdNode *G, DdNode *D));
+EXTERN int Cudd_bddLeqUnless ARGS((DdManager *dd, DdNode *f, DdNode *g, DdNode *D));
+EXTERN int Cudd_EqualSupNorm ARGS((DdManager *dd, DdNode *f, DdNode *g, CUDD_VALUE_TYPE tolerance, int pr));
+EXTERN DdNode * Cudd_bddMakePrime ARGS ((DdManager *dd, DdNode *cube, DdNode *f));
+EXTERN double * Cudd_CofMinterm ARGS((DdManager *dd, DdNode *node));
+EXTERN DdNode * Cudd_SolveEqn ARGS((DdManager * bdd, DdNode *F, DdNode *Y, DdNode **G, int **yIndex, int n));
+EXTERN DdNode * Cudd_VerifySol ARGS((DdManager * bdd, DdNode *F, DdNode **G, int *yIndex, int n));
+EXTERN DdNode * Cudd_SplitSet ARGS((DdManager *manager, DdNode *S, DdNode **xVars, int n, double m));
+EXTERN DdNode * Cudd_SubsetHeavyBranch ARGS((DdManager *dd, DdNode *f, int numVars, int threshold));
+EXTERN DdNode * Cudd_SupersetHeavyBranch ARGS((DdManager *dd, DdNode *f, int numVars, int threshold));
+EXTERN DdNode * Cudd_SubsetShortPaths ARGS((DdManager *dd, DdNode *f, int numVars, int threshold, int hardlimit));
+EXTERN DdNode * Cudd_SupersetShortPaths ARGS((DdManager *dd, DdNode *f, int numVars, int threshold, int hardlimit));
+EXTERN void Cudd_SymmProfile ARGS((DdManager *table, int lower, int upper));
+EXTERN unsigned int Cudd_Prime ARGS((unsigned int p));
+EXTERN int Cudd_PrintMinterm ARGS((DdManager *manager, DdNode *node));
+EXTERN int Cudd_bddPrintCover ARGS((DdManager *dd, DdNode *l, DdNode *u));
+EXTERN int Cudd_PrintDebug ARGS((DdManager *dd, DdNode *f, int n, int pr));
+EXTERN int Cudd_DagSize ARGS((DdNode *node));
+EXTERN int Cudd_EstimateCofactor ARGS((DdManager *dd, DdNode * node, int i, int phase));
+EXTERN int Cudd_EstimateCofactorSimple ARGS((DdNode * node, int i));
+EXTERN int Cudd_SharingSize ARGS((DdNode **nodeArray, int n));
+EXTERN double Cudd_CountMinterm ARGS((DdManager *manager, DdNode *node, int nvars));
+EXTERN int Cudd_EpdCountMinterm ARGS((DdManager *manager, DdNode *node, int nvars, EpDouble *epd));
+EXTERN double Cudd_CountPath ARGS((DdNode *node));
+EXTERN double Cudd_CountPathsToNonZero ARGS((DdNode *node));
+EXTERN DdNode * Cudd_Support ARGS((DdManager *dd, DdNode *f));
+EXTERN int * Cudd_SupportIndex ARGS((DdManager *dd, DdNode *f));
+EXTERN int Cudd_SupportSize ARGS((DdManager *dd, DdNode *f));
+EXTERN DdNode * Cudd_VectorSupport ARGS((DdManager *dd, DdNode **F, int n));
+EXTERN int * Cudd_VectorSupportIndex ARGS((DdManager *dd, DdNode **F, int n));
+EXTERN int Cudd_VectorSupportSize ARGS((DdManager *dd, DdNode **F, int n));
+EXTERN int Cudd_ClassifySupport ARGS((DdManager *dd, DdNode *f, DdNode *g, DdNode **common, DdNode **onlyF, DdNode **onlyG));
+EXTERN int Cudd_CountLeaves ARGS((DdNode *node));
+EXTERN int Cudd_bddPickOneCube ARGS((DdManager *ddm, DdNode *node, char *string));
+EXTERN DdNode * Cudd_bddPickOneMinterm ARGS((DdManager *dd, DdNode *f, DdNode **vars, int n));
+EXTERN DdNode ** Cudd_bddPickArbitraryMinterms ARGS((DdManager *dd, DdNode *f, DdNode **vars, int n, int k));
+EXTERN DdNode * Cudd_SubsetWithMaskVars ARGS((DdManager *dd, DdNode *f, DdNode **vars, int nvars, DdNode **maskVars, int mvars));
+EXTERN DdGen * Cudd_FirstCube ARGS((DdManager *dd, DdNode *f, int **cube, CUDD_VALUE_TYPE *value));
+EXTERN int Cudd_NextCube ARGS((DdGen *gen, int **cube, CUDD_VALUE_TYPE *value));
+EXTERN DdNode * Cudd_bddComputeCube ARGS((DdManager *dd, DdNode **vars, int *phase, int n));
+EXTERN DdNode * Cudd_addComputeCube ARGS((DdManager *dd, DdNode **vars, int *phase, int n));
+EXTERN DdNode * Cudd_CubeArrayToBdd ARGS((DdManager *dd, int *array));
+EXTERN int Cudd_BddToCubeArray ARGS((DdManager *dd, DdNode *cube, int *array));
+EXTERN DdGen * Cudd_FirstNode ARGS((DdManager *dd, DdNode *f, DdNode **node));
+EXTERN int Cudd_NextNode ARGS((DdGen *gen, DdNode **node));
+EXTERN int Cudd_GenFree ARGS((DdGen *gen));
+EXTERN int Cudd_IsGenEmpty ARGS((DdGen *gen));
+EXTERN DdNode * Cudd_IndicesToCube ARGS((DdManager *dd, int *array, int n));
+EXTERN void Cudd_PrintVersion ARGS((FILE *fp));
+EXTERN double Cudd_AverageDistance ARGS((DdManager *dd));
+EXTERN long Cudd_Random ARGS(());
+EXTERN void Cudd_Srandom ARGS((long seed));
+EXTERN double Cudd_Density ARGS((DdManager *dd, DdNode *f, int nvars));
+EXTERN void Cudd_OutOfMem ARGS((long size));
+EXTERN int Cudd_zddCount ARGS((DdManager *zdd, DdNode *P));
+EXTERN double Cudd_zddCountDouble ARGS((DdManager *zdd, DdNode *P));
+EXTERN DdNode * Cudd_zddProduct ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_zddUnateProduct ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_zddWeakDiv ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_zddDivide ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_zddWeakDivF ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_zddDivideF ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * Cudd_zddComplement ARGS((DdManager *dd, DdNode *node));
+EXTERN MtrNode * Cudd_MakeZddTreeNode ARGS((DdManager *dd, unsigned int low, unsigned int size, unsigned int type));
+EXTERN DdNode * Cudd_zddIsop ARGS((DdManager *dd, DdNode *L, DdNode *U, DdNode **zdd_I));
+EXTERN DdNode * Cudd_bddIsop ARGS((DdManager *dd, DdNode *L, DdNode *U));
+EXTERN DdNode * Cudd_MakeBddFromZddCover ARGS((DdManager *dd, DdNode *node));
+EXTERN int Cudd_zddDagSize ARGS((DdNode *p_node));
+EXTERN double Cudd_zddCountMinterm ARGS((DdManager *zdd, DdNode *node, int path));
+EXTERN void Cudd_zddPrintSubtable ARGS((DdManager *table));
+EXTERN DdNode * Cudd_zddPortFromBdd ARGS((DdManager *dd, DdNode *B));
+EXTERN DdNode * Cudd_zddPortToBdd ARGS((DdManager *dd, DdNode *f));
+EXTERN int Cudd_zddReduceHeap ARGS((DdManager *table, Cudd_ReorderingType heuristic, int minsize));
+EXTERN int Cudd_zddShuffleHeap ARGS((DdManager *table, int *permutation));
+EXTERN DdNode * Cudd_zddIte ARGS((DdManager *dd, DdNode *f, DdNode *g, DdNode *h));
+EXTERN DdNode * Cudd_zddUnion ARGS((DdManager *dd, DdNode *P, DdNode *Q));
+EXTERN DdNode * Cudd_zddIntersect ARGS((DdManager *dd, DdNode *P, DdNode *Q));
+EXTERN DdNode * Cudd_zddDiff ARGS((DdManager *dd, DdNode *P, DdNode *Q));
+EXTERN DdNode * Cudd_zddDiffConst ARGS((DdManager *zdd, DdNode *P, DdNode *Q));
+EXTERN DdNode * Cudd_zddSubset1 ARGS((DdManager *dd, DdNode *P, int var));
+EXTERN DdNode * Cudd_zddSubset0 ARGS((DdManager *dd, DdNode *P, int var));
+EXTERN DdNode * Cudd_zddChange ARGS((DdManager *dd, DdNode *P, int var));
+EXTERN void Cudd_zddSymmProfile ARGS((DdManager *table, int lower, int upper));
+EXTERN int Cudd_zddPrintMinterm ARGS((DdManager *zdd, DdNode *node));
+EXTERN int Cudd_zddPrintCover ARGS((DdManager *zdd, DdNode *node));
+EXTERN int Cudd_zddPrintDebug ARGS((DdManager *zdd, DdNode *f, int n, int pr));
+EXTERN DdGen * Cudd_zddFirstPath ARGS((DdManager *zdd, DdNode *f, int **path));
+EXTERN int Cudd_zddNextPath ARGS((DdGen *gen, int **path));
+EXTERN char * Cudd_zddCoverPathToString ARGS((DdManager *zdd, int *path, char *str));
+EXTERN int Cudd_zddDumpDot ARGS((DdManager *dd, int n, DdNode **f, char **inames, char **onames, FILE *fp));
+EXTERN int Cudd_bddSetPiVar ARGS((DdManager *dd, int index));
+EXTERN int Cudd_bddSetPsVar ARGS((DdManager *dd, int index));
+EXTERN int Cudd_bddSetNsVar ARGS((DdManager *dd, int index));
+EXTERN int Cudd_bddIsPiVar ARGS((DdManager *dd, int index));
+EXTERN int Cudd_bddIsPsVar ARGS((DdManager *dd, int index));
+EXTERN int Cudd_bddIsNsVar ARGS((DdManager *dd, int index));
+EXTERN int Cudd_bddSetPairIndex ARGS((DdManager *dd, int index, int pairIndex));
+EXTERN int Cudd_bddReadPairIndex ARGS((DdManager *dd, int index));
+EXTERN int Cudd_bddSetVarToBeGrouped ARGS((DdManager *dd, int index));
+EXTERN int Cudd_bddSetVarHardGroup ARGS((DdManager *dd, int index));
+EXTERN int Cudd_bddResetVarToBeGrouped ARGS((DdManager *dd, int index));
+EXTERN int Cudd_bddIsVarToBeGrouped ARGS((DdManager *dd, int index));
+EXTERN int Cudd_bddSetVarToBeUngrouped ARGS((DdManager *dd, int index));
+EXTERN int Cudd_bddIsVarToBeUngrouped ARGS((DdManager *dd, int index));
+EXTERN int Cudd_bddIsVarHardGroup ARGS((DdManager *dd, int index));
+
+/**AutomaticEnd***************************************************************/
+
+#endif /* _CUDD */
diff --git a/src/bdd/cudd/cudd.make b/src/bdd/cudd/cudd.make
new file mode 100644
index 00000000..7cb342a2
--- /dev/null
+++ b/src/bdd/cudd/cudd.make
@@ -0,0 +1,42 @@
+CSRC += cuddAPI.c cuddAddAbs.c cuddAddApply.c cuddAddFind.c cuddAddIte.c \
+ cuddAddInv.c cuddAddNeg.c cuddAddWalsh.c cuddAndAbs.c \
+ cuddAnneal.c cuddApa.c cuddApprox.c cuddBddAbs.c cuddBddCorr.c\
+ cuddBddIte.c cuddBridge.c cuddCache.c cuddCheck.c cuddClip.c \
+ cuddCof.c cuddCompose.c cuddDecomp.c cuddEssent.c cuddExact.c \
+ cuddExport.c cuddGenCof.c cuddGenetic.c \
+ cuddGroup.c cuddHarwell.c cuddInit.c cuddInteract.c \
+ cuddLCache.c cuddLevelQ.c \
+ cuddLinear.c cuddLiteral.c cuddMatMult.c cuddPriority.c \
+ cuddRead.c cuddRef.c cuddReorder.c cuddSat.c cuddSign.c \
+ cuddSolve.c cuddSplit.c cuddSubsetHB.c cuddSubsetSP.c cuddSymmetry.c \
+ cuddTable.c cuddUtil.c cuddWindow.c cuddZddCount.c cuddZddFuncs.c \
+ cuddZddGroup.c cuddZddIsop.c cuddZddLin.c cuddZddMisc.c cuddZddPort.c \
+ cuddZddReord.c cuddZddSetop.c cuddZddSymm.c cuddZddUtil.c
+
+HEADERS += cudd.h cuddInt.h
+MISC += testcudd.c r7x8.1.mat doc/cudd.ps doc/cuddAllAbs.html doc/cuddAllDet.html \
+ doc/cuddExtAbs.html doc/cuddExtDet.html doc/cuddIntro.css \
+ doc/cuddIntro.html doc/footnode.html doc/img1.gif doc/img2.gif \
+ doc/img3.gif doc/img4.gif doc/img5.gif doc/index.html \
+ doc/node1.html doc/node2.html doc/node3.html doc/node4.html \
+ doc/node5.html doc/node6.html doc/node7.html doc/node8.html \
+ doc/icons/change_begin.gif \
+ doc/icons/change_delete.gif \
+ doc/icons/change_end.gif \
+ doc/icons/contents_motif.gif \
+ doc/icons/cross_ref_motif.gif \
+ doc/icons/foot_motif.gif \
+ doc/icons/image.gif \
+ doc/icons/index_motif.gif \
+ doc/icons/next_group_motif.gif \
+ doc/icons/next_group_motif_gr.gif \
+ doc/icons/next_motif.gif \
+ doc/icons/next_motif_gr.gif \
+ doc/icons/previous_group_motif.gif \
+ doc/icons/previous_group_motif_gr.gif \
+ doc/icons/previous_motif.gif \
+ doc/icons/previous_motif_gr.gif \
+ doc/icons/up_motif.gif \
+ doc/icons/up_motif_gr.gif
+
+DEPENDENCYFILES = $(CSRC)
diff --git a/src/bdd/cudd/cuddAPI.c b/src/bdd/cudd/cuddAPI.c
new file mode 100644
index 00000000..2acde7cd
--- /dev/null
+++ b/src/bdd/cudd/cuddAPI.c
@@ -0,0 +1,4409 @@
+/**CFile***********************************************************************
+
+ FileName [cuddAPI.c]
+
+ PackageName [cudd]
+
+ Synopsis [Application interface functions.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_addNewVar()
+ <li> Cudd_addNewVarAtLevel()
+ <li> Cudd_bddNewVar()
+ <li> Cudd_bddNewVarAtLevel()
+ <li> Cudd_addIthVar()
+ <li> Cudd_bddIthVar()
+ <li> Cudd_zddIthVar()
+ <li> Cudd_zddVarsFromBddVars()
+ <li> Cudd_addConst()
+ <li> Cudd_IsNonConstant()
+ <li> Cudd_AutodynEnable()
+ <li> Cudd_AutodynDisable()
+ <li> Cudd_ReorderingStatus()
+ <li> Cudd_AutodynEnableZdd()
+ <li> Cudd_AutodynDisableZdd()
+ <li> Cudd_ReorderingStatusZdd()
+ <li> Cudd_zddRealignmentEnabled()
+ <li> Cudd_zddRealignEnable()
+ <li> Cudd_zddRealignDisable()
+ <li> Cudd_bddRealignmentEnabled()
+ <li> Cudd_bddRealignEnable()
+ <li> Cudd_bddRealignDisable()
+ <li> Cudd_ReadOne()
+ <li> Cudd_ReadZddOne()
+ <li> Cudd_ReadZero()
+ <li> Cudd_ReadLogicZero()
+ <li> Cudd_ReadPlusInfinity()
+ <li> Cudd_ReadMinusInfinity()
+ <li> Cudd_ReadBackground()
+ <li> Cudd_SetBackground()
+ <li> Cudd_ReadCacheSlots()
+ <li> Cudd_ReadCacheUsedSlots()
+ <li> Cudd_ReadCacheLookUps()
+ <li> Cudd_ReadCacheHits()
+ <li> Cudd_ReadMinHit()
+ <li> Cudd_SetMinHit()
+ <li> Cudd_ReadLooseUpTo()
+ <li> Cudd_SetLooseUpTo()
+ <li> Cudd_ReadMaxCache()
+ <li> Cudd_ReadMaxCacheHard()
+ <li> Cudd_SetMaxCacheHard()
+ <li> Cudd_ReadSize()
+ <li> Cudd_ReadSlots()
+ <li> Cudd_ReadUsedSlots()
+ <li> Cudd_ExpectedUsedSlots()
+ <li> Cudd_ReadKeys()
+ <li> Cudd_ReadDead()
+ <li> Cudd_ReadMinDead()
+ <li> Cudd_ReadReorderings()
+ <li> Cudd_ReadReorderingTime()
+ <li> Cudd_ReadGarbageCollections()
+ <li> Cudd_ReadGarbageCollectionTime()
+ <li> Cudd_ReadNodesFreed()
+ <li> Cudd_ReadNodesDropped()
+ <li> Cudd_ReadUniqueLookUps()
+ <li> Cudd_ReadUniqueLinks()
+ <li> Cudd_ReadSiftMaxVar()
+ <li> Cudd_SetSiftMaxVar()
+ <li> Cudd_ReadMaxGrowth()
+ <li> Cudd_SetMaxGrowth()
+ <li> Cudd_ReadMaxGrowthAlternate()
+ <li> Cudd_SetMaxGrowthAlternate()
+ <li> Cudd_ReadReorderingCycle()
+ <li> Cudd_SetReorderingCycle()
+ <li> Cudd_ReadTree()
+ <li> Cudd_SetTree()
+ <li> Cudd_FreeTree()
+ <li> Cudd_ReadZddTree()
+ <li> Cudd_SetZddTree()
+ <li> Cudd_FreeZddTree()
+ <li> Cudd_NodeReadIndex()
+ <li> Cudd_ReadPerm()
+ <li> Cudd_ReadInvPerm()
+ <li> Cudd_ReadVars()
+ <li> Cudd_ReadEpsilon()
+ <li> Cudd_SetEpsilon()
+ <li> Cudd_ReadGroupCheck()
+ <li> Cudd_SetGroupcheck()
+ <li> Cudd_GarbageCollectionEnabled()
+ <li> Cudd_EnableGarbageCollection()
+ <li> Cudd_DisableGarbageCollection()
+ <li> Cudd_DeadAreCounted()
+ <li> Cudd_TurnOnCountDead()
+ <li> Cudd_TurnOffCountDead()
+ <li> Cudd_ReadRecomb()
+ <li> Cudd_SetRecomb()
+ <li> Cudd_ReadSymmviolation()
+ <li> Cudd_SetSymmviolation()
+ <li> Cudd_ReadArcviolation()
+ <li> Cudd_SetArcviolation()
+ <li> Cudd_ReadPopulationSize()
+ <li> Cudd_SetPopulationSize()
+ <li> Cudd_ReadNumberXovers()
+ <li> Cudd_SetNumberXovers()
+ <li> Cudd_ReadMemoryInUse()
+ <li> Cudd_PrintInfo()
+ <li> Cudd_ReadPeakNodeCount()
+ <li> Cudd_ReadPeakLiveNodeCount()
+ <li> Cudd_ReadNodeCount()
+ <li> Cudd_zddReadNodeCount()
+ <li> Cudd_AddHook()
+ <li> Cudd_RemoveHook()
+ <li> Cudd_IsInHook()
+ <li> Cudd_StdPreReordHook()
+ <li> Cudd_StdPostReordHook()
+ <li> Cudd_EnableReorderingReporting()
+ <li> Cudd_DisableReorderingReporting()
+ <li> Cudd_ReorderingReporting()
+ <li> Cudd_ReadErrorCode()
+ <li> Cudd_ClearErrorCode()
+ <li> Cudd_ReadStdout()
+ <li> Cudd_SetStdout()
+ <li> Cudd_ReadStderr()
+ <li> Cudd_SetStderr()
+ <li> Cudd_ReadNextReordering()
+ <li> Cudd_SetNextReordering()
+ <li> Cudd_ReadSwapSteps()
+ <li> Cudd_ReadMaxLive()
+ <li> Cudd_SetMaxLive()
+ <li> Cudd_ReadMaxMemory()
+ <li> Cudd_SetMaxMemory()
+ <li> Cudd_bddBindVar()
+ <li> Cudd_bddUnbindVar()
+ <li> Cudd_bddVarIsBound()
+ <li> Cudd_bddSetPiVar()
+ <li> Cudd_bddSetPsVar()
+ <li> Cudd_bddSetNsVar()
+ <li> Cudd_bddIsPiVar()
+ <li> Cudd_bddIsPsVar()
+ <li> Cudd_bddIsNsVar()
+ <li> Cudd_bddSetPairIndex()
+ <li> Cudd_bddReadPairIndex()
+ <li> Cudd_bddSetVarToBeGrouped()
+ <li> Cudd_bddSetVarHardGroup()
+ <li> Cudd_bddResetVarToBeGrouped()
+ <li> Cudd_bddIsVarToBeGrouped()
+ <li> Cudd_bddSetVarToBeUngrouped()
+ <li> Cudd_bddIsVarToBeUngrouped()
+ <li> Cudd_bddIsVarHardGroup()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> fixVarTree()
+ </ul>]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddAPI.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static void fixVarTree ARGS((MtrNode *treenode, int *perm, int size));
+static int addMultiplicityGroups ARGS((DdManager *dd, MtrNode *treenode, int multiplicity, char *vmask, char *lmask));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns a new ADD variable.]
+
+ Description [Creates a new ADD variable. The new variable has an
+ index equal to the largest previous index plus 1. Returns a
+ pointer to the new variable if successful; NULL otherwise.
+ An ADD variable differs from a BDD variable because it points to the
+ arithmetic zero, instead of having a complement pointer to 1. ]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddNewVar Cudd_addIthVar Cudd_addConst
+ Cudd_addNewVarAtLevel]
+
+******************************************************************************/
+DdNode *
+Cudd_addNewVar(
+ DdManager * dd)
+{
+ DdNode *res;
+
+ if ((unsigned int) dd->size >= CUDD_MAXINDEX - 1) return(NULL);
+ do {
+ dd->reordered = 0;
+ res = cuddUniqueInter(dd,dd->size,DD_ONE(dd),DD_ZERO(dd));
+ } while (dd->reordered == 1);
+
+ return(res);
+
+} /* end of Cudd_addNewVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns a new ADD variable at a specified level.]
+
+ Description [Creates a new ADD variable. The new variable has an
+ index equal to the largest previous index plus 1 and is positioned at
+ the specified level in the order. Returns a pointer to the new
+ variable if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addNewVar Cudd_addIthVar Cudd_bddNewVarAtLevel]
+
+******************************************************************************/
+DdNode *
+Cudd_addNewVarAtLevel(
+ DdManager * dd,
+ int level)
+{
+ DdNode *res;
+
+ if ((unsigned int) dd->size >= CUDD_MAXINDEX - 1) return(NULL);
+ if (level >= dd->size) return(Cudd_addIthVar(dd,level));
+ if (!cuddInsertSubtables(dd,1,level)) return(NULL);
+ do {
+ dd->reordered = 0;
+ res = cuddUniqueInter(dd,dd->size - 1,DD_ONE(dd),DD_ZERO(dd));
+ } while (dd->reordered == 1);
+
+ return(res);
+
+} /* end of Cudd_addNewVarAtLevel */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns a new BDD variable.]
+
+ Description [Creates a new BDD variable. The new variable has an
+ index equal to the largest previous index plus 1. Returns a
+ pointer to the new variable if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addNewVar Cudd_bddIthVar Cudd_bddNewVarAtLevel]
+
+******************************************************************************/
+DdNode *
+Cudd_bddNewVar(
+ DdManager * dd)
+{
+ DdNode *res;
+
+ if ((unsigned int) dd->size >= CUDD_MAXINDEX - 1) return(NULL);
+ res = cuddUniqueInter(dd,dd->size,dd->one,Cudd_Not(dd->one));
+
+ return(res);
+
+} /* end of Cudd_bddNewVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns a new BDD variable at a specified level.]
+
+ Description [Creates a new BDD variable. The new variable has an
+ index equal to the largest previous index plus 1 and is positioned at
+ the specified level in the order. Returns a pointer to the new
+ variable if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddNewVar Cudd_bddIthVar Cudd_addNewVarAtLevel]
+
+******************************************************************************/
+DdNode *
+Cudd_bddNewVarAtLevel(
+ DdManager * dd,
+ int level)
+{
+ DdNode *res;
+
+ if ((unsigned int) dd->size >= CUDD_MAXINDEX - 1) return(NULL);
+ if (level >= dd->size) return(Cudd_bddIthVar(dd,level));
+ if (!cuddInsertSubtables(dd,1,level)) return(NULL);
+ res = dd->vars[dd->size - 1];
+
+ return(res);
+
+} /* end of Cudd_bddNewVarAtLevel */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the ADD variable with index i.]
+
+ Description [Retrieves the ADD variable with index i if it already
+ exists, or creates a new ADD variable. Returns a pointer to the
+ variable if successful; NULL otherwise. An ADD variable differs from
+ a BDD variable because it points to the arithmetic zero, instead of
+ having a complement pointer to 1. ]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addNewVar Cudd_bddIthVar Cudd_addConst
+ Cudd_addNewVarAtLevel]
+
+******************************************************************************/
+DdNode *
+Cudd_addIthVar(
+ DdManager * dd,
+ int i)
+{
+ DdNode *res;
+
+ if ((unsigned int) i >= CUDD_MAXINDEX - 1) return(NULL);
+ do {
+ dd->reordered = 0;
+ res = cuddUniqueInter(dd,i,DD_ONE(dd),DD_ZERO(dd));
+ } while (dd->reordered == 1);
+
+ return(res);
+
+} /* end of Cudd_addIthVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the BDD variable with index i.]
+
+ Description [Retrieves the BDD variable with index i if it already
+ exists, or creates a new BDD variable. Returns a pointer to the
+ variable if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddNewVar Cudd_addIthVar Cudd_bddNewVarAtLevel
+ Cudd_ReadVars]
+
+******************************************************************************/
+DdNode *
+Cudd_bddIthVar(
+ DdManager * dd,
+ int i)
+{
+ DdNode *res;
+
+ if ((unsigned int) i >= CUDD_MAXINDEX - 1) return(NULL);
+ if (i < dd->size) {
+ res = dd->vars[i];
+ } else {
+ res = cuddUniqueInter(dd,i,dd->one,Cudd_Not(dd->one));
+ }
+
+ return(res);
+
+} /* end of Cudd_bddIthVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the ZDD variable with index i.]
+
+ Description [Retrieves the ZDD variable with index i if it already
+ exists, or creates a new ZDD variable. Returns a pointer to the
+ variable if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddIthVar Cudd_addIthVar]
+
+******************************************************************************/
+DdNode *
+Cudd_zddIthVar(
+ DdManager * dd,
+ int i)
+{
+ DdNode *res;
+ DdNode *zvar;
+ DdNode *lower;
+ int j;
+
+ if ((unsigned int) i >= CUDD_MAXINDEX - 1) return(NULL);
+
+ /* The i-th variable function has the following structure:
+ ** at the level corresponding to index i there is a node whose "then"
+ ** child points to the universe, and whose "else" child points to zero.
+ ** Above that level there are nodes with identical children.
+ */
+
+ /* First we build the node at the level of index i. */
+ lower = (i < dd->sizeZ - 1) ? dd->univ[dd->permZ[i]+1] : DD_ONE(dd);
+ do {
+ dd->reordered = 0;
+ zvar = cuddUniqueInterZdd(dd, i, lower, DD_ZERO(dd));
+ } while (dd->reordered == 1);
+
+ if (zvar == NULL)
+ return(NULL);
+ cuddRef(zvar);
+
+ /* Now we add the "filler" nodes above the level of index i. */
+ for (j = dd->permZ[i] - 1; j >= 0; j--) {
+ do {
+ dd->reordered = 0;
+ res = cuddUniqueInterZdd(dd, dd->invpermZ[j], zvar, zvar);
+ } while (dd->reordered == 1);
+ if (res == NULL) {
+ Cudd_RecursiveDerefZdd(dd,zvar);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDerefZdd(dd,zvar);
+ zvar = res;
+ }
+ cuddDeref(zvar);
+ return(zvar);
+
+} /* end of Cudd_zddIthVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Creates one or more ZDD variables for each BDD variable.]
+
+ Description [Creates one or more ZDD variables for each BDD
+ variable. If some ZDD variables already exist, only the missing
+ variables are created. Parameter multiplicity allows the caller to
+ control how many variables are created for each BDD variable in
+ existence. For instance, if ZDDs are used to represent covers, two
+ ZDD variables are required for each BDD variable. The order of the
+ BDD variables is transferred to the ZDD variables. If a variable
+ group tree exists for the BDD variables, a corresponding ZDD
+ variable group tree is created by expanding the BDD variable
+ tree. In any case, the ZDD variables derived from the same BDD
+ variable are merged in a ZDD variable group. If a ZDD variable group
+ tree exists, it is freed. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddNewVar Cudd_bddIthVar Cudd_bddNewVarAtLevel]
+
+******************************************************************************/
+int
+Cudd_zddVarsFromBddVars(
+ DdManager * dd /* DD manager */,
+ int multiplicity /* how many ZDD variables are created for each BDD variable */)
+{
+ int res;
+ int i, j;
+ int allnew;
+ int *permutation;
+
+ if (multiplicity < 1) return(0);
+ allnew = dd->sizeZ == 0;
+ if (dd->size * multiplicity > dd->sizeZ) {
+ res = cuddResizeTableZdd(dd,dd->size * multiplicity - 1);
+ if (res == 0) return(0);
+ }
+ /* Impose the order of the BDD variables to the ZDD variables. */
+ if (allnew) {
+ for (i = 0; i < dd->size; i++) {
+ for (j = 0; j < multiplicity; j++) {
+ dd->permZ[i * multiplicity + j] =
+ dd->perm[i] * multiplicity + j;
+ dd->invpermZ[dd->permZ[i * multiplicity + j]] =
+ i * multiplicity + j;
+ }
+ }
+ for (i = 0; i < dd->sizeZ; i++) {
+ dd->univ[i]->index = dd->invpermZ[i];
+ }
+ } else {
+ permutation = ALLOC(int,dd->sizeZ);
+ if (permutation == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (i = 0; i < dd->size; i++) {
+ for (j = 0; j < multiplicity; j++) {
+ permutation[i * multiplicity + j] =
+ dd->invperm[i] * multiplicity + j;
+ }
+ }
+ for (i = dd->size * multiplicity; i < dd->sizeZ; i++) {
+ permutation[i] = i;
+ }
+ res = Cudd_zddShuffleHeap(dd, permutation);
+ FREE(permutation);
+ if (res == 0) return(0);
+ }
+ /* Copy and expand the variable group tree if it exists. */
+ if (dd->treeZ != NULL) {
+ Cudd_FreeZddTree(dd);
+ }
+ if (dd->tree != NULL) {
+ dd->treeZ = Mtr_CopyTree(dd->tree, multiplicity);
+ if (dd->treeZ == NULL) return(0);
+ } else if (multiplicity > 1) {
+ dd->treeZ = Mtr_InitGroupTree(0, dd->sizeZ);
+ if (dd->treeZ == NULL) return(0);
+ dd->treeZ->index = dd->invpermZ[0];
+ }
+ /* Create groups for the ZDD variables derived from the same BDD variable.
+ */
+ if (multiplicity > 1) {
+ char *vmask, *lmask;
+
+ vmask = ALLOC(char, dd->size);
+ if (vmask == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ lmask = ALLOC(char, dd->size);
+ if (lmask == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (i = 0; i < dd->size; i++) {
+ vmask[i] = lmask[i] = 0;
+ }
+ res = addMultiplicityGroups(dd,dd->treeZ,multiplicity,vmask,lmask);
+ FREE(vmask);
+ FREE(lmask);
+ if (res == 0) return(0);
+ }
+ return(1);
+
+} /* end of Cudd_zddVarsFromBddVars */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the ADD for constant c.]
+
+ Description [Retrieves the ADD for constant c if it already
+ exists, or creates a new ADD. Returns a pointer to the
+ ADD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addNewVar Cudd_addIthVar]
+
+******************************************************************************/
+DdNode *
+Cudd_addConst(
+ DdManager * dd,
+ CUDD_VALUE_TYPE c)
+{
+ return(cuddUniqueConst(dd,c));
+
+} /* end of Cudd_addConst */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns 1 if a DD node is not constant.]
+
+ Description [Returns 1 if a DD node is not constant. This function is
+ useful to test the results of Cudd_bddIteConstant, Cudd_addIteConstant,
+ Cudd_addEvalConst. These results may be a special value signifying
+ non-constant. In the other cases the macro Cudd_IsConstant can be used.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_IsConstant Cudd_bddIteConstant Cudd_addIteConstant
+ Cudd_addEvalConst]
+
+******************************************************************************/
+int
+Cudd_IsNonConstant(
+ DdNode *f)
+{
+ return(f == DD_NON_CONSTANT || !Cudd_IsConstant(f));
+
+} /* end of Cudd_IsNonConstant */
+
+
+/**Function********************************************************************
+
+ Synopsis [Enables automatic dynamic reordering of BDDs and ADDs.]
+
+ Description [Enables automatic dynamic reordering of BDDs and
+ ADDs. Parameter method is used to determine the method used for
+ reordering. If CUDD_REORDER_SAME is passed, the method is
+ unchanged.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_AutodynDisable Cudd_ReorderingStatus
+ Cudd_AutodynEnableZdd]
+
+******************************************************************************/
+void
+Cudd_AutodynEnable(
+ DdManager * unique,
+ Cudd_ReorderingType method)
+{
+ unique->autoDyn = 1;
+ if (method != CUDD_REORDER_SAME) {
+ unique->autoMethod = method;
+ }
+#ifndef DD_NO_DEATH_ROW
+ /* If reordering is enabled, using the death row causes too many
+ ** invocations. Hence, we shrink the death row to just one entry.
+ */
+ cuddClearDeathRow(unique);
+ unique->deathRowDepth = 1;
+ unique->deadMask = unique->deathRowDepth - 1;
+ if ((unsigned) unique->nextDead > unique->deadMask) {
+ unique->nextDead = 0;
+ }
+ unique->deathRow = REALLOC(DdNodePtr, unique->deathRow,
+ unique->deathRowDepth);
+#endif
+ return;
+
+} /* end of Cudd_AutodynEnable */
+
+
+/**Function********************************************************************
+
+ Synopsis [Disables automatic dynamic reordering.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_AutodynEnable Cudd_ReorderingStatus
+ Cudd_AutodynDisableZdd]
+
+******************************************************************************/
+void
+Cudd_AutodynDisable(
+ DdManager * unique)
+{
+ unique->autoDyn = 0;
+ return;
+
+} /* end of Cudd_AutodynDisable */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reports the status of automatic dynamic reordering of BDDs
+ and ADDs.]
+
+ Description [Reports the status of automatic dynamic reordering of
+ BDDs and ADDs. Parameter method is set to the reordering method
+ currently selected. Returns 1 if automatic reordering is enabled; 0
+ otherwise.]
+
+ SideEffects [Parameter method is set to the reordering method currently
+ selected.]
+
+ SeeAlso [Cudd_AutodynEnable Cudd_AutodynDisable
+ Cudd_ReorderingStatusZdd]
+
+******************************************************************************/
+int
+Cudd_ReorderingStatus(
+ DdManager * unique,
+ Cudd_ReorderingType * method)
+{
+ *method = unique->autoMethod;
+ return(unique->autoDyn);
+
+} /* end of Cudd_ReorderingStatus */
+
+
+/**Function********************************************************************
+
+ Synopsis [Enables automatic dynamic reordering of ZDDs.]
+
+ Description [Enables automatic dynamic reordering of ZDDs. Parameter
+ method is used to determine the method used for reordering ZDDs. If
+ CUDD_REORDER_SAME is passed, the method is unchanged.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_AutodynDisableZdd Cudd_ReorderingStatusZdd
+ Cudd_AutodynEnable]
+
+******************************************************************************/
+void
+Cudd_AutodynEnableZdd(
+ DdManager * unique,
+ Cudd_ReorderingType method)
+{
+ unique->autoDynZ = 1;
+ if (method != CUDD_REORDER_SAME) {
+ unique->autoMethodZ = method;
+ }
+ return;
+
+} /* end of Cudd_AutodynEnableZdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Disables automatic dynamic reordering of ZDDs.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_AutodynEnableZdd Cudd_ReorderingStatusZdd
+ Cudd_AutodynDisable]
+
+******************************************************************************/
+void
+Cudd_AutodynDisableZdd(
+ DdManager * unique)
+{
+ unique->autoDynZ = 0;
+ return;
+
+} /* end of Cudd_AutodynDisableZdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reports the status of automatic dynamic reordering of ZDDs.]
+
+ Description [Reports the status of automatic dynamic reordering of
+ ZDDs. Parameter method is set to the ZDD reordering method currently
+ selected. Returns 1 if automatic reordering is enabled; 0
+ otherwise.]
+
+ SideEffects [Parameter method is set to the ZDD reordering method currently
+ selected.]
+
+ SeeAlso [Cudd_AutodynEnableZdd Cudd_AutodynDisableZdd
+ Cudd_ReorderingStatus]
+
+******************************************************************************/
+int
+Cudd_ReorderingStatusZdd(
+ DdManager * unique,
+ Cudd_ReorderingType * method)
+{
+ *method = unique->autoMethodZ;
+ return(unique->autoDynZ);
+
+} /* end of Cudd_ReorderingStatusZdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Tells whether the realignment of ZDD order to BDD order is
+ enabled.]
+
+ Description [Returns 1 if the realignment of ZDD order to BDD order is
+ enabled; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddRealignEnable Cudd_zddRealignDisable
+ Cudd_bddRealignEnable Cudd_bddRealignDisable]
+
+******************************************************************************/
+int
+Cudd_zddRealignmentEnabled(
+ DdManager * unique)
+{
+ return(unique->realign);
+
+} /* end of Cudd_zddRealignmentEnabled */
+
+
+/**Function********************************************************************
+
+ Synopsis [Enables realignment of ZDD order to BDD order.]
+
+ Description [Enables realignment of the ZDD variable order to the
+ BDD variable order after the BDDs and ADDs have been reordered. The
+ number of ZDD variables must be a multiple of the number of BDD
+ variables for realignment to make sense. If this condition is not met,
+ Cudd_ReduceHeap will return 0. Let <code>M</code> be the
+ ratio of the two numbers. For the purpose of realignment, the ZDD
+ variables from <code>M*i</code> to <code>(M+1)*i-1</code> are
+ reagarded as corresponding to BDD variable <code>i</code>. Realignment
+ is initially disabled.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReduceHeap Cudd_zddRealignDisable
+ Cudd_zddRealignmentEnabled Cudd_bddRealignDisable
+ Cudd_bddRealignmentEnabled]
+
+******************************************************************************/
+void
+Cudd_zddRealignEnable(
+ DdManager * unique)
+{
+ unique->realign = 1;
+ return;
+
+} /* end of Cudd_zddRealignEnable */
+
+
+/**Function********************************************************************
+
+ Synopsis [Disables realignment of ZDD order to BDD order.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddRealignEnable Cudd_zddRealignmentEnabled
+ Cudd_bddRealignEnable Cudd_bddRealignmentEnabled]
+
+******************************************************************************/
+void
+Cudd_zddRealignDisable(
+ DdManager * unique)
+{
+ unique->realign = 0;
+ return;
+
+} /* end of Cudd_zddRealignDisable */
+
+
+/**Function********************************************************************
+
+ Synopsis [Tells whether the realignment of BDD order to ZDD order is
+ enabled.]
+
+ Description [Returns 1 if the realignment of BDD order to ZDD order is
+ enabled; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddRealignEnable Cudd_bddRealignDisable
+ Cudd_zddRealignEnable Cudd_zddRealignDisable]
+
+******************************************************************************/
+int
+Cudd_bddRealignmentEnabled(
+ DdManager * unique)
+{
+ return(unique->realignZ);
+
+} /* end of Cudd_bddRealignmentEnabled */
+
+
+/**Function********************************************************************
+
+ Synopsis [Enables realignment of BDD order to ZDD order.]
+
+ Description [Enables realignment of the BDD variable order to the
+ ZDD variable order after the ZDDs have been reordered. The
+ number of ZDD variables must be a multiple of the number of BDD
+ variables for realignment to make sense. If this condition is not met,
+ Cudd_zddReduceHeap will return 0. Let <code>M</code> be the
+ ratio of the two numbers. For the purpose of realignment, the ZDD
+ variables from <code>M*i</code> to <code>(M+1)*i-1</code> are
+ reagarded as corresponding to BDD variable <code>i</code>. Realignment
+ is initially disabled.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddReduceHeap Cudd_bddRealignDisable
+ Cudd_bddRealignmentEnabled Cudd_zddRealignDisable
+ Cudd_zddRealignmentEnabled]
+
+******************************************************************************/
+void
+Cudd_bddRealignEnable(
+ DdManager * unique)
+{
+ unique->realignZ = 1;
+ return;
+
+} /* end of Cudd_bddRealignEnable */
+
+
+/**Function********************************************************************
+
+ Synopsis [Disables realignment of ZDD order to BDD order.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddRealignEnable Cudd_bddRealignmentEnabled
+ Cudd_zddRealignEnable Cudd_zddRealignmentEnabled]
+
+******************************************************************************/
+void
+Cudd_bddRealignDisable(
+ DdManager * unique)
+{
+ unique->realignZ = 0;
+ return;
+
+} /* end of Cudd_bddRealignDisable */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the one constant of the manager.]
+
+ Description [Returns the one constant of the manager. The one
+ constant is common to ADDs and BDDs.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadZero Cudd_ReadLogicZero Cudd_ReadZddOne]
+
+******************************************************************************/
+DdNode *
+Cudd_ReadOne(
+ DdManager * dd)
+{
+ return(dd->one);
+
+} /* end of Cudd_ReadOne */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the ZDD for the constant 1 function.]
+
+ Description [Returns the ZDD for the constant 1 function.
+ The representation of the constant 1 function as a ZDD depends on
+ how many variables it (nominally) depends on. The index of the
+ topmost variable in the support is given as argument <code>i</code>.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadOne]
+
+******************************************************************************/
+DdNode *
+Cudd_ReadZddOne(
+ DdManager * dd,
+ int i)
+{
+ if (i < 0)
+ return(NULL);
+ return(i < dd->sizeZ ? dd->univ[i] : DD_ONE(dd));
+
+} /* end of Cudd_ReadZddOne */
+
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the zero constant of the manager.]
+
+ Description [Returns the zero constant of the manager. The zero
+ constant is the arithmetic zero, rather than the logic zero. The
+ latter is the complement of the one constant.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadOne Cudd_ReadLogicZero]
+
+******************************************************************************/
+DdNode *
+Cudd_ReadZero(
+ DdManager * dd)
+{
+ return(DD_ZERO(dd));
+
+} /* end of Cudd_ReadZero */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the logic zero constant of the manager.]
+
+ Description [Returns the zero constant of the manager. The logic zero
+ constant is the complement of the one constant, and is distinct from
+ the arithmetic zero.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadOne Cudd_ReadZero]
+
+******************************************************************************/
+DdNode *
+Cudd_ReadLogicZero(
+ DdManager * dd)
+{
+ return(Cudd_Not(DD_ONE(dd)));
+
+} /* end of Cudd_ReadLogicZero */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the plus-infinity constant from the manager.]
+
+ Description []
+
+ SideEffects [None]
+
+******************************************************************************/
+DdNode *
+Cudd_ReadPlusInfinity(
+ DdManager * dd)
+{
+ return(dd->plusinfinity);
+
+} /* end of Cudd_ReadPlusInfinity */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the minus-infinity constant from the manager.]
+
+ Description []
+
+ SideEffects [None]
+
+******************************************************************************/
+DdNode *
+Cudd_ReadMinusInfinity(
+ DdManager * dd)
+{
+ return(dd->minusinfinity);
+
+} /* end of Cudd_ReadMinusInfinity */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the background constant of the manager.]
+
+ Description []
+
+ SideEffects [None]
+
+******************************************************************************/
+DdNode *
+Cudd_ReadBackground(
+ DdManager * dd)
+{
+ return(dd->background);
+
+} /* end of Cudd_ReadBackground */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the background constant of the manager.]
+
+ Description [Sets the background constant of the manager. It assumes
+ that the DdNode pointer bck is already referenced.]
+
+ SideEffects [None]
+
+******************************************************************************/
+void
+Cudd_SetBackground(
+ DdManager * dd,
+ DdNode * bck)
+{
+ dd->background = bck;
+
+} /* end of Cudd_SetBackground */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the number of slots in the cache.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadCacheUsedSlots]
+
+******************************************************************************/
+unsigned int
+Cudd_ReadCacheSlots(
+ DdManager * dd)
+{
+ return(dd->cacheSlots);
+
+} /* end of Cudd_ReadCacheSlots */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the fraction of used slots in the cache.]
+
+ Description [Reads the fraction of used slots in the cache. The unused
+ slots are those in which no valid data is stored. Garbage collection,
+ variable reordering, and cache resizing may cause used slots to become
+ unused.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadCacheSlots]
+
+******************************************************************************/
+double
+Cudd_ReadCacheUsedSlots(
+ DdManager * dd)
+{
+ unsigned long used = 0;
+ int slots = dd->cacheSlots;
+ DdCache *cache = dd->cache;
+ int i;
+
+ for (i = 0; i < slots; i++) {
+ used += cache[i].h != 0;
+ }
+
+ return((double)used / (double) dd->cacheSlots);
+
+} /* end of Cudd_ReadCacheUsedSlots */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the number of cache look-ups.]
+
+ Description [Returns the number of cache look-ups.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadCacheHits]
+
+******************************************************************************/
+double
+Cudd_ReadCacheLookUps(
+ DdManager * dd)
+{
+ return(dd->cacheHits + dd->cacheMisses +
+ dd->totCachehits + dd->totCacheMisses);
+
+} /* end of Cudd_ReadCacheLookUps */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the number of cache hits.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadCacheLookUps]
+
+******************************************************************************/
+double
+Cudd_ReadCacheHits(
+ DdManager * dd)
+{
+ return(dd->cacheHits + dd->totCachehits);
+
+} /* end of Cudd_ReadCacheHits */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the number of recursive calls.]
+
+ Description [Returns the number of recursive calls if the package is
+ compiled with DD_COUNT defined.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+double
+Cudd_ReadRecursiveCalls(
+ DdManager * dd)
+{
+#ifdef DD_COUNT
+ return(dd->recursiveCalls);
+#else
+ return(-1.0);
+#endif
+
+} /* end of Cudd_ReadRecursiveCalls */
+
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the hit rate that causes resizinig of the computed
+ table.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetMinHit]
+
+******************************************************************************/
+unsigned int
+Cudd_ReadMinHit(
+ DdManager * dd)
+{
+ /* Internally, the package manipulates the ratio of hits to
+ ** misses instead of the ratio of hits to accesses. */
+ return((unsigned int) (0.5 + 100 * dd->minHit / (1 + dd->minHit)));
+
+} /* end of Cudd_ReadMinHit */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the hit rate that causes resizinig of the computed
+ table.]
+
+ Description [Sets the minHit parameter of the manager. This
+ parameter controls the resizing of the computed table. If the hit
+ rate is larger than the specified value, and the cache is not
+ already too large, then its size is doubled.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadMinHit]
+
+******************************************************************************/
+void
+Cudd_SetMinHit(
+ DdManager * dd,
+ unsigned int hr)
+{
+ /* Internally, the package manipulates the ratio of hits to
+ ** misses instead of the ratio of hits to accesses. */
+ dd->minHit = (double) hr / (100.0 - (double) hr);
+
+} /* end of Cudd_SetMinHit */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the looseUpTo parameter of the manager.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetLooseUpTo Cudd_ReadMinHit Cudd_ReadMinDead]
+
+******************************************************************************/
+unsigned int
+Cudd_ReadLooseUpTo(
+ DdManager * dd)
+{
+ return(dd->looseUpTo);
+
+} /* end of Cudd_ReadLooseUpTo */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the looseUpTo parameter of the manager.]
+
+ Description [Sets the looseUpTo parameter of the manager. This
+ parameter of the manager controls the threshold beyond which no fast
+ growth of the unique table is allowed. The threshold is given as a
+ number of slots. If the value passed to this function is 0, the
+ function determines a suitable value based on the available memory.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadLooseUpTo Cudd_SetMinHit]
+
+******************************************************************************/
+void
+Cudd_SetLooseUpTo(
+ DdManager * dd,
+ unsigned int lut)
+{
+ if (lut == 0) {
+ long datalimit = getSoftDataLimit();
+ lut = (unsigned int) (datalimit / (sizeof(DdNode) *
+ DD_MAX_LOOSE_FRACTION));
+ }
+ dd->looseUpTo = lut;
+
+} /* end of Cudd_SetLooseUpTo */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the soft limit for the cache size.]
+
+ Description [Returns the soft limit for the cache size. The soft limit]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadMaxCache]
+
+******************************************************************************/
+unsigned int
+Cudd_ReadMaxCache(
+ DdManager * dd)
+{
+ return(2 * dd->cacheSlots + dd->cacheSlack);
+
+} /* end of Cudd_ReadMaxCache */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the maxCacheHard parameter of the manager.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetMaxCacheHard Cudd_ReadMaxCache]
+
+******************************************************************************/
+unsigned int
+Cudd_ReadMaxCacheHard(
+ DdManager * dd)
+{
+ return(dd->maxCacheHard);
+
+} /* end of Cudd_ReadMaxCache */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the maxCacheHard parameter of the manager.]
+
+ Description [Sets the maxCacheHard parameter of the manager. The
+ cache cannot grow larger than maxCacheHard entries. This parameter
+ allows an application to control the trade-off of memory versus
+ speed. If the value passed to this function is 0, the function
+ determines a suitable maximum cache size based on the available memory.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadMaxCacheHard Cudd_SetMaxCache]
+
+******************************************************************************/
+void
+Cudd_SetMaxCacheHard(
+ DdManager * dd,
+ unsigned int mc)
+{
+ if (mc == 0) {
+ long datalimit = getSoftDataLimit();
+ mc = (unsigned int) (datalimit / (sizeof(DdCache) *
+ DD_MAX_CACHE_FRACTION));
+ }
+ dd->maxCacheHard = mc;
+
+} /* end of Cudd_SetMaxCacheHard */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the number of BDD variables in existance.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadZddSize]
+
+******************************************************************************/
+int
+Cudd_ReadSize(
+ DdManager * dd)
+{
+ return(dd->size);
+
+} /* end of Cudd_ReadSize */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the number of ZDD variables in existance.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadSize]
+
+******************************************************************************/
+int
+Cudd_ReadZddSize(
+ DdManager * dd)
+{
+ return(dd->sizeZ);
+
+} /* end of Cudd_ReadZddSize */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the total number of slots of the unique table.]
+
+ Description [Returns the total number of slots of the unique table.
+ This number ismainly for diagnostic purposes.]
+
+ SideEffects [None]
+
+******************************************************************************/
+unsigned int
+Cudd_ReadSlots(
+ DdManager * dd)
+{
+ return(dd->slots);
+
+} /* end of Cudd_ReadSlots */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the fraction of used slots in the unique table.]
+
+ Description [Reads the fraction of used slots in the unique
+ table. The unused slots are those in which no valid data is
+ stored. Garbage collection, variable reordering, and subtable
+ resizing may cause used slots to become unused.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadSlots]
+
+******************************************************************************/
+double
+Cudd_ReadUsedSlots(
+ DdManager * dd)
+{
+ unsigned long used = 0;
+ int i, j;
+ int size = dd->size;
+ DdNodePtr *nodelist;
+ DdSubtable *subtable;
+ DdNode *node;
+ DdNode *sentinel = &(dd->sentinel);
+
+ /* Scan each BDD/ADD subtable. */
+ for (i = 0; i < size; i++) {
+ subtable = &(dd->subtables[i]);
+ nodelist = subtable->nodelist;
+ for (j = 0; (unsigned) j < subtable->slots; j++) {
+ node = nodelist[j];
+ if (node != sentinel) {
+ used++;
+ }
+ }
+ }
+
+ /* Scan the ZDD subtables. */
+ size = dd->sizeZ;
+
+ for (i = 0; i < size; i++) {
+ subtable = &(dd->subtableZ[i]);
+ nodelist = subtable->nodelist;
+ for (j = 0; (unsigned) j < subtable->slots; j++) {
+ node = nodelist[j];
+ if (node != NULL) {
+ used++;
+ }
+ }
+ }
+
+ /* Constant table. */
+ subtable = &(dd->constants);
+ nodelist = subtable->nodelist;
+ for (j = 0; (unsigned) j < subtable->slots; j++) {
+ node = nodelist[j];
+ if (node != NULL) {
+ used++;
+ }
+ }
+
+ return((double)used / (double) dd->slots);
+
+} /* end of Cudd_ReadUsedSlots */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the expected fraction of used slots in the unique
+ table.]
+
+ Description [Computes the fraction of slots in the unique table that
+ should be in use. This expected value is based on the assumption
+ that the hash function distributes the keys randomly; it can be
+ compared with the result of Cudd_ReadUsedSlots to monitor the
+ performance of the unique table hash function.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadSlots Cudd_ReadUsedSlots]
+
+******************************************************************************/
+double
+Cudd_ExpectedUsedSlots(
+ DdManager * dd)
+{
+ int i;
+ int size = dd->size;
+ DdSubtable *subtable;
+ double empty = 0.0;
+
+ /* To each subtable we apply the corollary to Theorem 8.5 (occupancy
+ ** distribution) from Sedgewick and Flajolet's Analysis of Algorithms.
+ ** The corollary says that for a a table with M buckets and a load ratio
+ ** of r, the expected number of empty buckets is asymptotically given
+ ** by M * exp(-r).
+ */
+
+ /* Scan each BDD/ADD subtable. */
+ for (i = 0; i < size; i++) {
+ subtable = &(dd->subtables[i]);
+ empty += (double) subtable->slots *
+ exp(-(double) subtable->keys / (double) subtable->slots);
+ }
+
+ /* Scan the ZDD subtables. */
+ size = dd->sizeZ;
+
+ for (i = 0; i < size; i++) {
+ subtable = &(dd->subtableZ[i]);
+ empty += (double) subtable->slots *
+ exp(-(double) subtable->keys / (double) subtable->slots);
+ }
+
+ /* Constant table. */
+ subtable = &(dd->constants);
+ empty += (double) subtable->slots *
+ exp(-(double) subtable->keys / (double) subtable->slots);
+
+ return(1.0 - empty / (double) dd->slots);
+
+} /* end of Cudd_ExpectedUsedSlots */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the number of nodes in the unique table.]
+
+ Description [Returns the total number of nodes currently in the unique
+ table, including the dead nodes.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadDead]
+
+******************************************************************************/
+unsigned int
+Cudd_ReadKeys(
+ DdManager * dd)
+{
+ return(dd->keys);
+
+} /* end of Cudd_ReadKeys */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the number of dead nodes in the unique table.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadKeys]
+
+******************************************************************************/
+unsigned int
+Cudd_ReadDead(
+ DdManager * dd)
+{
+ return(dd->dead);
+
+} /* end of Cudd_ReadDead */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the minDead parameter of the manager.]
+
+ Description [Reads the minDead parameter of the manager. The minDead
+ parameter is used by the package to decide whether to collect garbage
+ or resize a subtable of the unique table when the subtable becomes
+ too full. The application can indirectly control the value of minDead
+ by setting the looseUpTo parameter.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadDead Cudd_ReadLooseUpTo Cudd_SetLooseUpTo]
+
+******************************************************************************/
+unsigned int
+Cudd_ReadMinDead(
+ DdManager * dd)
+{
+ return(dd->minDead);
+
+} /* end of Cudd_ReadMinDead */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the number of times reordering has occurred.]
+
+ Description [Returns the number of times reordering has occurred in the
+ manager. The number includes both the calls to Cudd_ReduceHeap from
+ the application program and those automatically performed by the
+ package. However, calls that do not even initiate reordering are not
+ counted. A call may not initiate reordering if there are fewer than
+ minsize live nodes in the manager, or if CUDD_REORDER_NONE is specified
+ as reordering method. The calls to Cudd_ShuffleHeap are not counted.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReduceHeap Cudd_ReadReorderingTime]
+
+******************************************************************************/
+int
+Cudd_ReadReorderings(
+ DdManager * dd)
+{
+ return(dd->reorderings);
+
+} /* end of Cudd_ReadReorderings */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the time spent in reordering.]
+
+ Description [Returns the number of milliseconds spent reordering
+ variables since the manager was initialized. The time spent in collecting
+ garbage before reordering is included.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadReorderings]
+
+******************************************************************************/
+long
+Cudd_ReadReorderingTime(
+ DdManager * dd)
+{
+ return(dd->reordTime);
+
+} /* end of Cudd_ReadReorderingTime */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the number of times garbage collection has occurred.]
+
+ Description [Returns the number of times garbage collection has
+ occurred in the manager. The number includes both the calls from
+ reordering procedures and those caused by requests to create new
+ nodes.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadGarbageCollectionTime]
+
+******************************************************************************/
+int
+Cudd_ReadGarbageCollections(
+ DdManager * dd)
+{
+ return(dd->garbageCollections);
+
+} /* end of Cudd_ReadGarbageCollections */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the time spent in garbage collection.]
+
+ Description [Returns the number of milliseconds spent doing garbage
+ collection since the manager was initialized.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadGarbageCollections]
+
+******************************************************************************/
+long
+Cudd_ReadGarbageCollectionTime(
+ DdManager * dd)
+{
+ return(dd->GCTime);
+
+} /* end of Cudd_ReadGarbageCollectionTime */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the number of nodes freed.]
+
+ Description [Returns the number of nodes returned to the free list if the
+ keeping of this statistic is enabled; -1 otherwise. This statistic is
+ enabled only if the package is compiled with DD_STATS defined.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadNodesDropped]
+
+******************************************************************************/
+double
+Cudd_ReadNodesFreed(
+ DdManager * dd)
+{
+#ifdef DD_STATS
+ return(dd->nodesFreed);
+#else
+ return(-1.0);
+#endif
+
+} /* end of Cudd_ReadNodesFreed */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the number of nodes dropped.]
+
+ Description [Returns the number of nodes killed by dereferencing if the
+ keeping of this statistic is enabled; -1 otherwise. This statistic is
+ enabled only if the package is compiled with DD_STATS defined.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadNodesFreed]
+
+******************************************************************************/
+double
+Cudd_ReadNodesDropped(
+ DdManager * dd)
+{
+#ifdef DD_STATS
+ return(dd->nodesDropped);
+#else
+ return(-1.0);
+#endif
+
+} /* end of Cudd_ReadNodesDropped */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the number of look-ups in the unique table.]
+
+ Description [Returns the number of look-ups in the unique table if the
+ keeping of this statistic is enabled; -1 otherwise. This statistic is
+ enabled only if the package is compiled with DD_UNIQUE_PROFILE defined.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadUniqueLinks]
+
+******************************************************************************/
+double
+Cudd_ReadUniqueLookUps(
+ DdManager * dd)
+{
+#ifdef DD_UNIQUE_PROFILE
+ return(dd->uniqueLookUps);
+#else
+ return(-1.0);
+#endif
+
+} /* end of Cudd_ReadUniqueLookUps */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the number of links followed in the unique table.]
+
+ Description [Returns the number of links followed during look-ups in the
+ unique table if the keeping of this statistic is enabled; -1 otherwise.
+ If an item is found in the first position of its collision list, the
+ number of links followed is taken to be 0. If it is in second position,
+ the number of links is 1, and so on. This statistic is enabled only if
+ the package is compiled with DD_UNIQUE_PROFILE defined.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadUniqueLookUps]
+
+******************************************************************************/
+double
+Cudd_ReadUniqueLinks(
+ DdManager * dd)
+{
+#ifdef DD_UNIQUE_PROFILE
+ return(dd->uniqueLinks);
+#else
+ return(-1.0);
+#endif
+
+} /* end of Cudd_ReadUniqueLinks */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the siftMaxVar parameter of the manager.]
+
+ Description [Reads the siftMaxVar parameter of the manager. This
+ parameter gives the maximum number of variables that will be sifted
+ for each invocation of sifting.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadSiftMaxSwap Cudd_SetSiftMaxVar]
+
+******************************************************************************/
+int
+Cudd_ReadSiftMaxVar(
+ DdManager * dd)
+{
+ return(dd->siftMaxVar);
+
+} /* end of Cudd_ReadSiftMaxVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the siftMaxVar parameter of the manager.]
+
+ Description [Sets the siftMaxVar parameter of the manager. This
+ parameter gives the maximum number of variables that will be sifted
+ for each invocation of sifting.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetSiftMaxSwap Cudd_ReadSiftMaxVar]
+
+******************************************************************************/
+void
+Cudd_SetSiftMaxVar(
+ DdManager * dd,
+ int smv)
+{
+ dd->siftMaxVar = smv;
+
+} /* end of Cudd_SetSiftMaxVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the siftMaxSwap parameter of the manager.]
+
+ Description [Reads the siftMaxSwap parameter of the manager. This
+ parameter gives the maximum number of swaps that will be attempted
+ for each invocation of sifting. The real number of swaps may exceed
+ the set limit because the package will always complete the sifting
+ of the variable that causes the limit to be reached.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadSiftMaxVar Cudd_SetSiftMaxSwap]
+
+******************************************************************************/
+int
+Cudd_ReadSiftMaxSwap(
+ DdManager * dd)
+{
+ return(dd->siftMaxSwap);
+
+} /* end of Cudd_ReadSiftMaxSwap */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the siftMaxSwap parameter of the manager.]
+
+ Description [Sets the siftMaxSwap parameter of the manager. This
+ parameter gives the maximum number of swaps that will be attempted
+ for each invocation of sifting. The real number of swaps may exceed
+ the set limit because the package will always complete the sifting
+ of the variable that causes the limit to be reached.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetSiftMaxVar Cudd_ReadSiftMaxSwap]
+
+******************************************************************************/
+void
+Cudd_SetSiftMaxSwap(
+ DdManager * dd,
+ int sms)
+{
+ dd->siftMaxSwap = sms;
+
+} /* end of Cudd_SetSiftMaxSwap */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the maxGrowth parameter of the manager.]
+
+ Description [Reads the maxGrowth parameter of the manager. This
+ parameter determines how much the number of nodes can grow during
+ sifting of a variable. Overall, sifting never increases the size of
+ the decision diagrams. This parameter only refers to intermediate
+ results. A lower value will speed up sifting, possibly at the
+ expense of quality.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetMaxGrowth Cudd_ReadMaxGrowthAlternate]
+
+******************************************************************************/
+double
+Cudd_ReadMaxGrowth(
+ DdManager * dd)
+{
+ return(dd->maxGrowth);
+
+} /* end of Cudd_ReadMaxGrowth */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the maxGrowth parameter of the manager.]
+
+ Description [Sets the maxGrowth parameter of the manager. This
+ parameter determines how much the number of nodes can grow during
+ sifting of a variable. Overall, sifting never increases the size of
+ the decision diagrams. This parameter only refers to intermediate
+ results. A lower value will speed up sifting, possibly at the
+ expense of quality.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadMaxGrowth Cudd_SetMaxGrowthAlternate]
+
+******************************************************************************/
+void
+Cudd_SetMaxGrowth(
+ DdManager * dd,
+ double mg)
+{
+ dd->maxGrowth = mg;
+
+} /* end of Cudd_SetMaxGrowth */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the maxGrowthAlt parameter of the manager.]
+
+ Description [Reads the maxGrowthAlt parameter of the manager. This
+ parameter is analogous to the maxGrowth paramter, and is used every
+ given number of reorderings instead of maxGrowth. The number of
+ reorderings is set with Cudd_SetReorderingCycle. If the number of
+ reorderings is 0 (default) maxGrowthAlt is never used.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadMaxGrowth Cudd_SetMaxGrowthAlternate
+ Cudd_SetReorderingCycle Cudd_ReadReorderingCycle]
+
+******************************************************************************/
+double
+Cudd_ReadMaxGrowthAlternate(
+ DdManager * dd)
+{
+ return(dd->maxGrowthAlt);
+
+} /* end of Cudd_ReadMaxGrowthAlternate */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the maxGrowthAlt parameter of the manager.]
+
+ Description [Sets the maxGrowthAlt parameter of the manager. This
+ parameter is analogous to the maxGrowth paramter, and is used every
+ given number of reorderings instead of maxGrowth. The number of
+ reorderings is set with Cudd_SetReorderingCycle. If the number of
+ reorderings is 0 (default) maxGrowthAlt is never used.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadMaxGrowthAlternate Cudd_SetMaxGrowth
+ Cudd_SetReorderingCycle Cudd_ReadReorderingCycle]
+
+******************************************************************************/
+void
+Cudd_SetMaxGrowthAlternate(
+ DdManager * dd,
+ double mg)
+{
+ dd->maxGrowthAlt = mg;
+
+} /* end of Cudd_SetMaxGrowthAlternate */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the reordCycle parameter of the manager.]
+
+ Description [Reads the reordCycle parameter of the manager. This
+ parameter determines how often the alternate threshold on maximum
+ growth is used in reordering.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadMaxGrowthAlternate Cudd_SetMaxGrowthAlternate
+ Cudd_SetReorderingCycle]
+
+******************************************************************************/
+int
+Cudd_ReadReorderingCycle(
+ DdManager * dd)
+{
+ return(dd->reordCycle);
+
+} /* end of Cudd_ReadReorderingCycle */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the reordCycle parameter of the manager.]
+
+ Description [Sets the reordCycle parameter of the manager. This
+ parameter determines how often the alternate threshold on maximum
+ growth is used in reordering.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadMaxGrowthAlternate Cudd_SetMaxGrowthAlternate
+ Cudd_ReadReorderingCycle]
+
+******************************************************************************/
+void
+Cudd_SetReorderingCycle(
+ DdManager * dd,
+ int cycle)
+{
+ dd->reordCycle = cycle;
+
+} /* end of Cudd_SetReorderingCycle */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the variable group tree of the manager.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetTree Cudd_FreeTree Cudd_ReadZddTree]
+
+******************************************************************************/
+MtrNode *
+Cudd_ReadTree(
+ DdManager * dd)
+{
+ return(dd->tree);
+
+} /* end of Cudd_ReadTree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the variable group tree of the manager.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_FreeTree Cudd_ReadTree Cudd_SetZddTree]
+
+******************************************************************************/
+void
+Cudd_SetTree(
+ DdManager * dd,
+ MtrNode * tree)
+{
+ if (dd->tree != NULL) {
+ Mtr_FreeTree(dd->tree);
+ }
+ dd->tree = tree;
+ if (tree == NULL) return;
+
+ fixVarTree(tree, dd->perm, dd->size);
+ return;
+
+} /* end of Cudd_SetTree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees the variable group tree of the manager.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetTree Cudd_ReadTree Cudd_FreeZddTree]
+
+******************************************************************************/
+void
+Cudd_FreeTree(
+ DdManager * dd)
+{
+ if (dd->tree != NULL) {
+ Mtr_FreeTree(dd->tree);
+ dd->tree = NULL;
+ }
+ return;
+
+} /* end of Cudd_FreeTree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the variable group tree of the manager.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetZddTree Cudd_FreeZddTree Cudd_ReadTree]
+
+******************************************************************************/
+MtrNode *
+Cudd_ReadZddTree(
+ DdManager * dd)
+{
+ return(dd->treeZ);
+
+} /* end of Cudd_ReadZddTree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the ZDD variable group tree of the manager.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_FreeZddTree Cudd_ReadZddTree Cudd_SetTree]
+
+******************************************************************************/
+void
+Cudd_SetZddTree(
+ DdManager * dd,
+ MtrNode * tree)
+{
+ if (dd->treeZ != NULL) {
+ Mtr_FreeTree(dd->treeZ);
+ }
+ dd->treeZ = tree;
+ if (tree == NULL) return;
+
+ fixVarTree(tree, dd->permZ, dd->sizeZ);
+ return;
+
+} /* end of Cudd_SetZddTree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees the variable group tree of the manager.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetZddTree Cudd_ReadZddTree Cudd_FreeTree]
+
+******************************************************************************/
+void
+Cudd_FreeZddTree(
+ DdManager * dd)
+{
+ if (dd->treeZ != NULL) {
+ Mtr_FreeTree(dd->treeZ);
+ dd->treeZ = NULL;
+ }
+ return;
+
+} /* end of Cudd_FreeZddTree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the index of the node.]
+
+ Description [Returns the index of the node. The node pointer can be
+ either regular or complemented.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadIndex]
+
+******************************************************************************/
+unsigned int
+Cudd_NodeReadIndex(
+ DdNode * node)
+{
+ return((unsigned int) Cudd_Regular(node)->index);
+
+} /* end of Cudd_NodeReadIndex */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the current position of the i-th variable in the
+ order.]
+
+ Description [Returns the current position of the i-th variable in
+ the order. If the index is CUDD_CONST_INDEX, returns
+ CUDD_CONST_INDEX; otherwise, if the index is out of bounds returns
+ -1.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadInvPerm Cudd_ReadPermZdd]
+
+******************************************************************************/
+int
+Cudd_ReadPerm(
+ DdManager * dd,
+ int i)
+{
+ if (i == CUDD_CONST_INDEX) return(CUDD_CONST_INDEX);
+ if (i < 0 || i >= dd->size) return(-1);
+ return(dd->perm[i]);
+
+} /* end of Cudd_ReadPerm */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the current position of the i-th ZDD variable in the
+ order.]
+
+ Description [Returns the current position of the i-th ZDD variable
+ in the order. If the index is CUDD_CONST_INDEX, returns
+ CUDD_CONST_INDEX; otherwise, if the index is out of bounds returns
+ -1.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadInvPermZdd Cudd_ReadPerm]
+
+******************************************************************************/
+int
+Cudd_ReadPermZdd(
+ DdManager * dd,
+ int i)
+{
+ if (i == CUDD_CONST_INDEX) return(CUDD_CONST_INDEX);
+ if (i < 0 || i >= dd->sizeZ) return(-1);
+ return(dd->permZ[i]);
+
+} /* end of Cudd_ReadPermZdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the index of the variable currently in the i-th
+ position of the order.]
+
+ Description [Returns the index of the variable currently in the i-th
+ position of the order. If the index is CUDD_CONST_INDEX, returns
+ CUDD_CONST_INDEX; otherwise, if the index is out of bounds returns -1.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadPerm Cudd_ReadInvPermZdd]
+
+******************************************************************************/
+int
+Cudd_ReadInvPerm(
+ DdManager * dd,
+ int i)
+{
+ if (i == CUDD_CONST_INDEX) return(CUDD_CONST_INDEX);
+ if (i < 0 || i >= dd->size) return(-1);
+ return(dd->invperm[i]);
+
+} /* end of Cudd_ReadInvPerm */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the index of the ZDD variable currently in the i-th
+ position of the order.]
+
+ Description [Returns the index of the ZDD variable currently in the
+ i-th position of the order. If the index is CUDD_CONST_INDEX, returns
+ CUDD_CONST_INDEX; otherwise, if the index is out of bounds returns -1.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadPerm Cudd_ReadInvPermZdd]
+
+******************************************************************************/
+int
+Cudd_ReadInvPermZdd(
+ DdManager * dd,
+ int i)
+{
+ if (i == CUDD_CONST_INDEX) return(CUDD_CONST_INDEX);
+ if (i < 0 || i >= dd->sizeZ) return(-1);
+ return(dd->invpermZ[i]);
+
+} /* end of Cudd_ReadInvPermZdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the i-th element of the vars array.]
+
+ Description [Returns the i-th element of the vars array if it falls
+ within the array bounds; NULL otherwise. If i is the index of an
+ existing variable, this function produces the same result as
+ Cudd_bddIthVar. However, if the i-th var does not exist yet,
+ Cudd_bddIthVar will create it, whereas Cudd_ReadVars will not.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddIthVar]
+
+******************************************************************************/
+DdNode *
+Cudd_ReadVars(
+ DdManager * dd,
+ int i)
+{
+ if (i < 0 || i > dd->size) return(NULL);
+ return(dd->vars[i]);
+
+} /* end of Cudd_ReadVars */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the epsilon parameter of the manager.]
+
+ Description [Reads the epsilon parameter of the manager. The epsilon
+ parameter control the comparison between floating point numbers.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetEpsilon]
+
+******************************************************************************/
+CUDD_VALUE_TYPE
+Cudd_ReadEpsilon(
+ DdManager * dd)
+{
+ return(dd->epsilon);
+
+} /* end of Cudd_ReadEpsilon */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the epsilon parameter of the manager to ep.]
+
+ Description [Sets the epsilon parameter of the manager to ep. The epsilon
+ parameter control the comparison between floating point numbers.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadEpsilon]
+
+******************************************************************************/
+void
+Cudd_SetEpsilon(
+ DdManager * dd,
+ CUDD_VALUE_TYPE ep)
+{
+ dd->epsilon = ep;
+
+} /* end of Cudd_SetEpsilon */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the groupcheck parameter of the manager.]
+
+ Description [Reads the groupcheck parameter of the manager. The
+ groupcheck parameter determines the aggregation criterion in group
+ sifting.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetGroupcheck]
+
+******************************************************************************/
+Cudd_AggregationType
+Cudd_ReadGroupcheck(
+ DdManager * dd)
+{
+ return(dd->groupcheck);
+
+} /* end of Cudd_ReadGroupCheck */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the parameter groupcheck of the manager to gc.]
+
+ Description [Sets the parameter groupcheck of the manager to gc. The
+ groupcheck parameter determines the aggregation criterion in group
+ sifting.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadGroupCheck]
+
+******************************************************************************/
+void
+Cudd_SetGroupcheck(
+ DdManager * dd,
+ Cudd_AggregationType gc)
+{
+ dd->groupcheck = gc;
+
+} /* end of Cudd_SetGroupcheck */
+
+
+/**Function********************************************************************
+
+ Synopsis [Tells whether garbage collection is enabled.]
+
+ Description [Returns 1 if garbage collection is enabled; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_EnableGarbageCollection Cudd_DisableGarbageCollection]
+
+******************************************************************************/
+int
+Cudd_GarbageCollectionEnabled(
+ DdManager * dd)
+{
+ return(dd->gcEnabled);
+
+} /* end of Cudd_GarbageCollectionEnabled */
+
+
+/**Function********************************************************************
+
+ Synopsis [Enables garbage collection.]
+
+ Description [Enables garbage collection. Garbage collection is
+ initially enabled. Therefore it is necessary to call this function
+ only if garbage collection has been explicitly disabled.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DisableGarbageCollection Cudd_GarbageCollectionEnabled]
+
+******************************************************************************/
+void
+Cudd_EnableGarbageCollection(
+ DdManager * dd)
+{
+ dd->gcEnabled = 1;
+
+} /* end of Cudd_EnableGarbageCollection */
+
+
+/**Function********************************************************************
+
+ Synopsis [Disables garbage collection.]
+
+ Description [Disables garbage collection. Garbage collection is
+ initially enabled. This function may be called to disable it.
+ However, garbage collection will still occur when a new node must be
+ created and no memory is left, or when garbage collection is required
+ for correctness. (E.g., before reordering.)]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_EnableGarbageCollection Cudd_GarbageCollectionEnabled]
+
+******************************************************************************/
+void
+Cudd_DisableGarbageCollection(
+ DdManager * dd)
+{
+ dd->gcEnabled = 0;
+
+} /* end of Cudd_DisableGarbageCollection */
+
+
+/**Function********************************************************************
+
+ Synopsis [Tells whether dead nodes are counted towards triggering
+ reordering.]
+
+ Description [Tells whether dead nodes are counted towards triggering
+ reordering. Returns 1 if dead nodes are counted; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_TurnOnCountDead Cudd_TurnOffCountDead]
+
+******************************************************************************/
+int
+Cudd_DeadAreCounted(
+ DdManager * dd)
+{
+ return(dd->countDead == 0 ? 1 : 0);
+
+} /* end of Cudd_DeadAreCounted */
+
+
+/**Function********************************************************************
+
+ Synopsis [Causes the dead nodes to be counted towards triggering
+ reordering.]
+
+ Description [Causes the dead nodes to be counted towards triggering
+ reordering. This causes more frequent reorderings. By default dead
+ nodes are not counted.]
+
+ SideEffects [Changes the manager.]
+
+ SeeAlso [Cudd_TurnOffCountDead Cudd_DeadAreCounted]
+
+******************************************************************************/
+void
+Cudd_TurnOnCountDead(
+ DdManager * dd)
+{
+ dd->countDead = 0;
+
+} /* end of Cudd_TurnOnCountDead */
+
+
+/**Function********************************************************************
+
+ Synopsis [Causes the dead nodes not to be counted towards triggering
+ reordering.]
+
+ Description [Causes the dead nodes not to be counted towards
+ triggering reordering. This causes less frequent reorderings. By
+ default dead nodes are not counted. Therefore there is no need to
+ call this function unless Cudd_TurnOnCountDead has been previously
+ called.]
+
+ SideEffects [Changes the manager.]
+
+ SeeAlso [Cudd_TurnOnCountDead Cudd_DeadAreCounted]
+
+******************************************************************************/
+void
+Cudd_TurnOffCountDead(
+ DdManager * dd)
+{
+ dd->countDead = ~0;
+
+} /* end of Cudd_TurnOffCountDead */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the current value of the recombination parameter used
+ in group sifting.]
+
+ Description [Returns the current value of the recombination
+ parameter used in group sifting. A larger (positive) value makes the
+ aggregation of variables due to the second difference criterion more
+ likely. A smaller (negative) value makes aggregation less likely.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetRecomb]
+
+******************************************************************************/
+int
+Cudd_ReadRecomb(
+ DdManager * dd)
+{
+ return(dd->recomb);
+
+} /* end of Cudd_ReadRecomb */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the value of the recombination parameter used in group
+ sifting.]
+
+ Description [Sets the value of the recombination parameter used in
+ group sifting. A larger (positive) value makes the aggregation of
+ variables due to the second difference criterion more likely. A
+ smaller (negative) value makes aggregation less likely. The default
+ value is 0.]
+
+ SideEffects [Changes the manager.]
+
+ SeeAlso [Cudd_ReadRecomb]
+
+******************************************************************************/
+void
+Cudd_SetRecomb(
+ DdManager * dd,
+ int recomb)
+{
+ dd->recomb = recomb;
+
+} /* end of Cudd_SetRecomb */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the current value of the symmviolation parameter used
+ in group sifting.]
+
+ Description [Returns the current value of the symmviolation
+ parameter. This parameter is used in group sifting to decide how
+ many violations to the symmetry conditions <code>f10 = f01</code> or
+ <code>f11 = f00</code> are tolerable when checking for aggregation
+ due to extended symmetry. The value should be between 0 and 100. A
+ small value causes fewer variables to be aggregated. The default
+ value is 0.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetSymmviolation]
+
+******************************************************************************/
+int
+Cudd_ReadSymmviolation(
+ DdManager * dd)
+{
+ return(dd->symmviolation);
+
+} /* end of Cudd_ReadSymmviolation */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the value of the symmviolation parameter used
+ in group sifting.]
+
+ Description [Sets the value of the symmviolation
+ parameter. This parameter is used in group sifting to decide how
+ many violations to the symmetry conditions <code>f10 = f01</code> or
+ <code>f11 = f00</code> are tolerable when checking for aggregation
+ due to extended symmetry. The value should be between 0 and 100. A
+ small value causes fewer variables to be aggregated. The default
+ value is 0.]
+
+ SideEffects [Changes the manager.]
+
+ SeeAlso [Cudd_ReadSymmviolation]
+
+******************************************************************************/
+void
+Cudd_SetSymmviolation(
+ DdManager * dd,
+ int symmviolation)
+{
+ dd->symmviolation = symmviolation;
+
+} /* end of Cudd_SetSymmviolation */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the current value of the arcviolation parameter used
+ in group sifting.]
+
+ Description [Returns the current value of the arcviolation
+ parameter. This parameter is used in group sifting to decide how
+ many arcs into <code>y</code> not coming from <code>x</code> are
+ tolerable when checking for aggregation due to extended
+ symmetry. The value should be between 0 and 100. A small value
+ causes fewer variables to be aggregated. The default value is 0.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetArcviolation]
+
+******************************************************************************/
+int
+Cudd_ReadArcviolation(
+ DdManager * dd)
+{
+ return(dd->arcviolation);
+
+} /* end of Cudd_ReadArcviolation */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the value of the arcviolation parameter used
+ in group sifting.]
+
+ Description [Sets the value of the arcviolation
+ parameter. This parameter is used in group sifting to decide how
+ many arcs into <code>y</code> not coming from <code>x</code> are
+ tolerable when checking for aggregation due to extended
+ symmetry. The value should be between 0 and 100. A small value
+ causes fewer variables to be aggregated. The default value is 0.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadArcviolation]
+
+******************************************************************************/
+void
+Cudd_SetArcviolation(
+ DdManager * dd,
+ int arcviolation)
+{
+ dd->arcviolation = arcviolation;
+
+} /* end of Cudd_SetArcviolation */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the current size of the population used by the
+ genetic algorithm for reordering.]
+
+ Description [Reads the current size of the population used by the
+ genetic algorithm for variable reordering. A larger population size will
+ cause the genetic algorithm to take more time, but will generally
+ produce better results. The default value is 0, in which case the
+ package uses three times the number of variables as population size,
+ with a maximum of 120.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetPopulationSize]
+
+******************************************************************************/
+int
+Cudd_ReadPopulationSize(
+ DdManager * dd)
+{
+ return(dd->populationSize);
+
+} /* end of Cudd_ReadPopulationSize */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the size of the population used by the
+ genetic algorithm for reordering.]
+
+ Description [Sets the size of the population used by the
+ genetic algorithm for variable reordering. A larger population size will
+ cause the genetic algorithm to take more time, but will generally
+ produce better results. The default value is 0, in which case the
+ package uses three times the number of variables as population size,
+ with a maximum of 120.]
+
+ SideEffects [Changes the manager.]
+
+ SeeAlso [Cudd_ReadPopulationSize]
+
+******************************************************************************/
+void
+Cudd_SetPopulationSize(
+ DdManager * dd,
+ int populationSize)
+{
+ dd->populationSize = populationSize;
+
+} /* end of Cudd_SetPopulationSize */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the current number of crossovers used by the
+ genetic algorithm for reordering.]
+
+ Description [Reads the current number of crossovers used by the
+ genetic algorithm for variable reordering. A larger number of crossovers will
+ cause the genetic algorithm to take more time, but will generally
+ produce better results. The default value is 0, in which case the
+ package uses three times the number of variables as number of crossovers,
+ with a maximum of 60.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetNumberXovers]
+
+******************************************************************************/
+int
+Cudd_ReadNumberXovers(
+ DdManager * dd)
+{
+ return(dd->numberXovers);
+
+} /* end of Cudd_ReadNumberXovers */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the number of crossovers used by the
+ genetic algorithm for reordering.]
+
+ Description [Sets the number of crossovers used by the genetic
+ algorithm for variable reordering. A larger number of crossovers
+ will cause the genetic algorithm to take more time, but will
+ generally produce better results. The default value is 0, in which
+ case the package uses three times the number of variables as number
+ of crossovers, with a maximum of 60.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadNumberXovers]
+
+******************************************************************************/
+void
+Cudd_SetNumberXovers(
+ DdManager * dd,
+ int numberXovers)
+{
+ dd->numberXovers = numberXovers;
+
+} /* end of Cudd_SetNumberXovers */
+
+/**Function********************************************************************
+
+ Synopsis [Returns the memory in use by the manager measured in bytes.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+long
+Cudd_ReadMemoryInUse(
+ DdManager * dd)
+{
+ return(dd->memused);
+
+} /* end of Cudd_ReadMemoryInUse */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints out statistics and settings for a CUDD manager.]
+
+ Description [Prints out statistics and settings for a CUDD manager.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+Cudd_PrintInfo(
+ DdManager * dd,
+ FILE * fp)
+{
+ int retval;
+ Cudd_ReorderingType autoMethod, autoMethodZ;
+
+ /* Modifiable parameters. */
+ retval = fprintf(fp,"**** CUDD modifiable parameters ****\n");
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Hard limit for cache size: %u\n",
+ Cudd_ReadMaxCacheHard(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Cache hit threshold for resizing: %u%%\n",
+ Cudd_ReadMinHit(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Garbage collection enabled: %s\n",
+ Cudd_GarbageCollectionEnabled(dd) ? "yes" : "no");
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Limit for fast unique table growth: %u\n",
+ Cudd_ReadLooseUpTo(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,
+ "Maximum number of variables sifted per reordering: %d\n",
+ Cudd_ReadSiftMaxVar(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,
+ "Maximum number of variable swaps per reordering: %d\n",
+ Cudd_ReadSiftMaxSwap(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Maximum growth while sifting a variable: %g\n",
+ Cudd_ReadMaxGrowth(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Dynamic reordering of BDDs enabled: %s\n",
+ Cudd_ReorderingStatus(dd,&autoMethod) ? "yes" : "no");
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Default BDD reordering method: %d\n", autoMethod);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Dynamic reordering of ZDDs enabled: %s\n",
+ Cudd_ReorderingStatusZdd(dd,&autoMethodZ) ? "yes" : "no");
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Default ZDD reordering method: %d\n", autoMethodZ);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Realignment of ZDDs to BDDs enabled: %s\n",
+ Cudd_zddRealignmentEnabled(dd) ? "yes" : "no");
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Realignment of BDDs to ZDDs enabled: %s\n",
+ Cudd_bddRealignmentEnabled(dd) ? "yes" : "no");
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Dead nodes counted in triggering reordering: %s\n",
+ Cudd_DeadAreCounted(dd) ? "yes" : "no");
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Group checking criterion: %d\n",
+ Cudd_ReadGroupcheck(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Recombination threshold: %d\n", Cudd_ReadRecomb(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Symmetry violation threshold: %d\n",
+ Cudd_ReadSymmviolation(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Arc violation threshold: %d\n",
+ Cudd_ReadArcviolation(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"GA population size: %d\n",
+ Cudd_ReadPopulationSize(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Number of crossovers for GA: %d\n",
+ Cudd_ReadNumberXovers(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Next reordering threshold: %u\n",
+ Cudd_ReadNextReordering(dd));
+ if (retval == EOF) return(0);
+
+ /* Non-modifiable parameters. */
+ retval = fprintf(fp,"**** CUDD non-modifiable parameters ****\n");
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Memory in use: %ld\n", Cudd_ReadMemoryInUse(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Peak number of nodes: %ld\n",
+ Cudd_ReadPeakNodeCount(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Peak number of live nodes: %d\n",
+ Cudd_ReadPeakLiveNodeCount(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Number of BDD variables: %d\n", dd->size);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Number of ZDD variables: %d\n", dd->sizeZ);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Number of cache entries: %u\n", dd->cacheSlots);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Number of cache look-ups: %.0f\n",
+ Cudd_ReadCacheLookUps(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Number of cache hits: %.0f\n",
+ Cudd_ReadCacheHits(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Number of cache insertions: %.0f\n",
+ dd->cacheinserts);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Number of cache collisions: %.0f\n",
+ dd->cachecollisions);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Number of cache deletions: %.0f\n",
+ dd->cachedeletions);
+ if (retval == EOF) return(0);
+ retval = cuddCacheProfile(dd,fp);
+ if (retval == 0) return(0);
+ retval = fprintf(fp,"Soft limit for cache size: %u\n",
+ Cudd_ReadMaxCache(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Number of buckets in unique table: %u\n", dd->slots);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Used buckets in unique table: %.2f%% (expected %.2f%%)\n",
+ 100.0 * Cudd_ReadUsedSlots(dd),
+ 100.0 * Cudd_ExpectedUsedSlots(dd));
+ if (retval == EOF) return(0);
+#ifdef DD_UNIQUE_PROFILE
+ retval = fprintf(fp,"Unique lookups: %.0f\n", dd->uniqueLookUps);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Unique links: %.0f (%g per lookup)\n",
+ dd->uniqueLinks, dd->uniqueLinks / dd->uniqueLookUps);
+ if (retval == EOF) return(0);
+#endif
+ retval = fprintf(fp,"Number of BDD and ADD nodes: %u\n", dd->keys);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Number of ZDD nodes: %u\n", dd->keysZ);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Number of dead BDD and ADD nodes: %u\n", dd->dead);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Number of dead ZDD nodes: %u\n", dd->deadZ);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Total number of nodes allocated: %.0f\n",
+ dd->allocated);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Total number of nodes reclaimed: %.0f\n",
+ dd->reclaimed);
+ if (retval == EOF) return(0);
+#if DD_STATS
+ retval = fprintf(fp,"Nodes freed: %.0f\n", dd->nodesFreed);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Nodes dropped: %.0f\n", dd->nodesDropped);
+ if (retval == EOF) return(0);
+#endif
+#if DD_COUNT
+ retval = fprintf(fp,"Number of recursive calls: %.0f\n",
+ Cudd_ReadRecursiveCalls(dd));
+ if (retval == EOF) return(0);
+#endif
+ retval = fprintf(fp,"Garbage collections so far: %d\n",
+ Cudd_ReadGarbageCollections(dd));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Time for garbage collection: %.2f sec\n",
+ ((double)Cudd_ReadGarbageCollectionTime(dd)/1000.0));
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Reorderings so far: %d\n", dd->reorderings);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Time for reordering: %.2f sec\n",
+ ((double)Cudd_ReadReorderingTime(dd)/1000.0));
+ if (retval == EOF) return(0);
+#if DD_COUNT
+ retval = fprintf(fp,"Node swaps in reordering: %.0f\n",
+ Cudd_ReadSwapSteps(dd));
+ if (retval == EOF) return(0);
+#endif
+
+ return(1);
+
+} /* end of Cudd_PrintInfo */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reports the peak number of nodes.]
+
+ Description [Reports the peak number of nodes. This number includes
+ node on the free list. At the peak, the number of nodes on the free
+ list is guaranteed to be less than DD_MEM_CHUNK.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadNodeCount Cudd_PrintInfo]
+
+******************************************************************************/
+long
+Cudd_ReadPeakNodeCount(
+ DdManager * dd)
+{
+ long count = 0;
+ DdNodePtr *scan = dd->memoryList;
+
+ while (scan != NULL) {
+ count += DD_MEM_CHUNK;
+ scan = (DdNodePtr *) *scan;
+ }
+ return(count);
+
+} /* end of Cudd_ReadPeakNodeCount */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reports the peak number of live nodes.]
+
+ Description [Reports the peak number of live nodes. This count is kept
+ only if CUDD is compiled with DD_STATS defined. If DD_STATS is not
+ defined, this function returns -1.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadNodeCount Cudd_PrintInfo Cudd_ReadPeakNodeCount]
+
+******************************************************************************/
+int
+Cudd_ReadPeakLiveNodeCount(
+ DdManager * dd)
+{
+ unsigned int live = dd->keys - dd->dead;
+
+ if (live > dd->peakLiveNodes) {
+ dd->peakLiveNodes = live;
+ }
+ return((int)dd->peakLiveNodes);
+
+} /* end of Cudd_ReadPeakLiveNodeCount */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reports the number of nodes in BDDs and ADDs.]
+
+ Description [Reports the number of live nodes in BDDs and ADDs. This
+ number does not include the isolated projection functions and the
+ unused constants. These nodes that are not counted are not part of
+ the DDs manipulated by the application.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadPeakNodeCount Cudd_zddReadNodeCount]
+
+******************************************************************************/
+long
+Cudd_ReadNodeCount(
+ DdManager * dd)
+{
+ long count;
+ int i;
+
+#ifndef DD_NO_DEATH_ROW
+ cuddClearDeathRow(dd);
+#endif
+
+ count = dd->keys - dd->dead;
+
+ /* Count isolated projection functions. Their number is subtracted
+ ** from the node count because they are not part of the BDDs.
+ */
+ for (i=0; i < dd->size; i++) {
+ if (dd->vars[i]->ref == 1) count--;
+ }
+ /* Subtract from the count the unused constants. */
+ if (DD_ZERO(dd)->ref == 1) count--;
+ if (DD_PLUS_INFINITY(dd)->ref == 1) count--;
+ if (DD_MINUS_INFINITY(dd)->ref == 1) count--;
+
+ return(count);
+
+} /* end of Cudd_ReadNodeCount */
+
+
+
+/**Function********************************************************************
+
+ Synopsis [Reports the number of nodes in ZDDs.]
+
+ Description [Reports the number of nodes in ZDDs. This
+ number always includes the two constants 1 and 0.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadPeakNodeCount Cudd_ReadNodeCount]
+
+******************************************************************************/
+long
+Cudd_zddReadNodeCount(
+ DdManager * dd)
+{
+ return(dd->keysZ - dd->deadZ + 2);
+
+} /* end of Cudd_zddReadNodeCount */
+
+
+/**Function********************************************************************
+
+ Synopsis [Adds a function to a hook.]
+
+ Description [Adds a function to a hook. A hook is a list of
+ application-provided functions called on certain occasions by the
+ package. Returns 1 if the function is successfully added; 2 if the
+ function was already in the list; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_RemoveHook]
+
+******************************************************************************/
+int
+Cudd_AddHook(
+ DdManager * dd,
+ int (*f)(DdManager *, char *, void *) ,
+ Cudd_HookType where)
+{
+ DdHook **hook, *nextHook, *newHook;
+
+ switch (where) {
+ case CUDD_PRE_GC_HOOK:
+ hook = &(dd->preGCHook);
+ break;
+ case CUDD_POST_GC_HOOK:
+ hook = &(dd->postGCHook);
+ break;
+ case CUDD_PRE_REORDERING_HOOK:
+ hook = &(dd->preReorderingHook);
+ break;
+ case CUDD_POST_REORDERING_HOOK:
+ hook = &(dd->postReorderingHook);
+ break;
+ default:
+ return(0);
+ }
+ /* Scan the list and find whether the function is already there.
+ ** If so, just return. */
+ nextHook = *hook;
+ while (nextHook != NULL) {
+ if (nextHook->f == f) {
+ return(2);
+ }
+ hook = &(nextHook->next);
+ nextHook = nextHook->next;
+ }
+ /* The function was not in the list. Create a new item and append it
+ ** to the end of the list. */
+ newHook = ALLOC(DdHook,1);
+ if (newHook == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ newHook->next = NULL;
+ newHook->f = f;
+ *hook = newHook;
+ return(1);
+
+} /* end of Cudd_AddHook */
+
+
+/**Function********************************************************************
+
+ Synopsis [Removes a function from a hook.]
+
+ Description [Removes a function from a hook. A hook is a list of
+ application-provided functions called on certain occasions by the
+ package. Returns 1 if successful; 0 the function was not in the list.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_AddHook]
+
+******************************************************************************/
+int
+Cudd_RemoveHook(
+ DdManager * dd,
+ int (*f)(DdManager *, char *, void *) ,
+ Cudd_HookType where)
+{
+ DdHook **hook, *nextHook;
+
+ switch (where) {
+ case CUDD_PRE_GC_HOOK:
+ hook = &(dd->preGCHook);
+ break;
+ case CUDD_POST_GC_HOOK:
+ hook = &(dd->postGCHook);
+ break;
+ case CUDD_PRE_REORDERING_HOOK:
+ hook = &(dd->preReorderingHook);
+ break;
+ case CUDD_POST_REORDERING_HOOK:
+ hook = &(dd->postReorderingHook);
+ break;
+ default:
+ return(0);
+ }
+ nextHook = *hook;
+ while (nextHook != NULL) {
+ if (nextHook->f == f) {
+ *hook = nextHook->next;
+ FREE(nextHook);
+ return(1);
+ }
+ hook = &(nextHook->next);
+ nextHook = nextHook->next;
+ }
+
+ return(0);
+
+} /* end of Cudd_RemoveHook */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether a function is in a hook.]
+
+ Description [Checks whether a function is in a hook. A hook is a list of
+ application-provided functions called on certain occasions by the
+ package. Returns 1 if the function is found; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_AddHook Cudd_RemoveHook]
+
+******************************************************************************/
+int
+Cudd_IsInHook(
+ DdManager * dd,
+ int (*f)(DdManager *, char *, void *) ,
+ Cudd_HookType where)
+{
+ DdHook *hook;
+
+ switch (where) {
+ case CUDD_PRE_GC_HOOK:
+ hook = dd->preGCHook;
+ break;
+ case CUDD_POST_GC_HOOK:
+ hook = dd->postGCHook;
+ break;
+ case CUDD_PRE_REORDERING_HOOK:
+ hook = dd->preReorderingHook;
+ break;
+ case CUDD_POST_REORDERING_HOOK:
+ hook = dd->postReorderingHook;
+ break;
+ default:
+ return(0);
+ }
+ /* Scan the list and find whether the function is already there. */
+ while (hook != NULL) {
+ if (hook->f == f) {
+ return(1);
+ }
+ hook = hook->next;
+ }
+ return(0);
+
+} /* end of Cudd_IsInHook */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sample hook function to call before reordering.]
+
+ Description [Sample hook function to call before reordering.
+ Prints on the manager's stdout reordering method and initial size.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_StdPostReordHook]
+
+******************************************************************************/
+int
+Cudd_StdPreReordHook(
+ DdManager *dd,
+ char *str,
+ void *data)
+{
+ Cudd_ReorderingType method = (Cudd_ReorderingType) (ptruint) data;
+ int retval;
+
+ retval = fprintf(dd->out,"%s reordering with ", str);
+ if (retval == EOF) return(0);
+ switch (method) {
+ case CUDD_REORDER_SIFT_CONVERGE:
+ case CUDD_REORDER_SYMM_SIFT_CONV:
+ case CUDD_REORDER_GROUP_SIFT_CONV:
+ case CUDD_REORDER_WINDOW2_CONV:
+ case CUDD_REORDER_WINDOW3_CONV:
+ case CUDD_REORDER_WINDOW4_CONV:
+ case CUDD_REORDER_LINEAR_CONVERGE:
+ retval = fprintf(dd->out,"converging ");
+ if (retval == EOF) return(0);
+ break;
+ default:
+ break;
+ }
+ switch (method) {
+ case CUDD_REORDER_RANDOM:
+ case CUDD_REORDER_RANDOM_PIVOT:
+ retval = fprintf(dd->out,"random");
+ break;
+ case CUDD_REORDER_SIFT:
+ case CUDD_REORDER_SIFT_CONVERGE:
+ retval = fprintf(dd->out,"sifting");
+ break;
+ case CUDD_REORDER_SYMM_SIFT:
+ case CUDD_REORDER_SYMM_SIFT_CONV:
+ retval = fprintf(dd->out,"symmetric sifting");
+ break;
+ case CUDD_REORDER_LAZY_SIFT:
+ retval = fprintf(dd->out,"lazy sifting");
+ break;
+ case CUDD_REORDER_GROUP_SIFT:
+ case CUDD_REORDER_GROUP_SIFT_CONV:
+ retval = fprintf(dd->out,"group sifting");
+ break;
+ case CUDD_REORDER_WINDOW2:
+ case CUDD_REORDER_WINDOW3:
+ case CUDD_REORDER_WINDOW4:
+ case CUDD_REORDER_WINDOW2_CONV:
+ case CUDD_REORDER_WINDOW3_CONV:
+ case CUDD_REORDER_WINDOW4_CONV:
+ retval = fprintf(dd->out,"window");
+ break;
+ case CUDD_REORDER_ANNEALING:
+ retval = fprintf(dd->out,"annealing");
+ break;
+ case CUDD_REORDER_GENETIC:
+ retval = fprintf(dd->out,"genetic");
+ break;
+ case CUDD_REORDER_LINEAR:
+ case CUDD_REORDER_LINEAR_CONVERGE:
+ retval = fprintf(dd->out,"linear sifting");
+ break;
+ case CUDD_REORDER_EXACT:
+ retval = fprintf(dd->out,"exact");
+ break;
+ default:
+ return(0);
+ }
+ if (retval == EOF) return(0);
+
+ retval = fprintf(dd->out,": from %ld to ... ", strcmp(str, "BDD") == 0 ?
+ Cudd_ReadNodeCount(dd) : Cudd_zddReadNodeCount(dd));
+ if (retval == EOF) return(0);
+ fflush(dd->out);
+ return(1);
+
+} /* end of Cudd_StdPreReordHook */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sample hook function to call after reordering.]
+
+ Description [Sample hook function to call after reordering.
+ Prints on the manager's stdout final size and reordering time.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_StdPreReordHook]
+
+******************************************************************************/
+int
+Cudd_StdPostReordHook(
+ DdManager *dd,
+ char *str,
+ void *data)
+{
+ long initialTime = (long) data;
+ int retval;
+ long finalTime = util_cpu_time();
+ double totalTimeSec = (double)(finalTime - initialTime) / 1000.0;
+
+ retval = fprintf(dd->out,"%ld nodes in %g sec\n", strcmp(str, "BDD") == 0 ?
+ Cudd_ReadNodeCount(dd) : Cudd_zddReadNodeCount(dd),
+ totalTimeSec);
+ if (retval == EOF) return(0);
+ retval = fflush(dd->out);
+ if (retval == EOF) return(0);
+ return(1);
+
+} /* end of Cudd_StdPostReordHook */
+
+
+/**Function********************************************************************
+
+ Synopsis [Enables reporting of reordering stats.]
+
+ Description [Enables reporting of reordering stats.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [Installs functions in the pre-reordering and post-reordering
+ hooks.]
+
+ SeeAlso [Cudd_DisableReorderingReporting Cudd_ReorderingReporting]
+
+******************************************************************************/
+int
+Cudd_EnableReorderingReporting(
+ DdManager *dd)
+{
+ if (!Cudd_AddHook(dd, Cudd_StdPreReordHook, CUDD_PRE_REORDERING_HOOK)) {
+ return(0);
+ }
+ if (!Cudd_AddHook(dd, Cudd_StdPostReordHook, CUDD_POST_REORDERING_HOOK)) {
+ return(0);
+ }
+ return(1);
+
+} /* end of Cudd_EnableReorderingReporting */
+
+
+/**Function********************************************************************
+
+ Synopsis [Disables reporting of reordering stats.]
+
+ Description [Disables reporting of reordering stats.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [Removes functions from the pre-reordering and post-reordering
+ hooks.]
+
+ SeeAlso [Cudd_EnableReorderingReporting Cudd_ReorderingReporting]
+
+******************************************************************************/
+int
+Cudd_DisableReorderingReporting(
+ DdManager *dd)
+{
+ if (!Cudd_RemoveHook(dd, Cudd_StdPreReordHook, CUDD_PRE_REORDERING_HOOK)) {
+ return(0);
+ }
+ if (!Cudd_RemoveHook(dd, Cudd_StdPostReordHook, CUDD_POST_REORDERING_HOOK)) {
+ return(0);
+ }
+ return(1);
+
+} /* end of Cudd_DisableReorderingReporting */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns 1 if reporting of reordering stats is enabled.]
+
+ Description [Returns 1 if reporting of reordering stats is enabled;
+ 0 otherwise.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_EnableReorderingReporting Cudd_DisableReorderingReporting]
+
+******************************************************************************/
+int
+Cudd_ReorderingReporting(
+ DdManager *dd)
+{
+ return(Cudd_IsInHook(dd, Cudd_StdPreReordHook, CUDD_PRE_REORDERING_HOOK));
+
+} /* end of Cudd_ReorderingReporting */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the code of the last error.]
+
+ Description [Returns the code of the last error. The error codes are
+ defined in cudd.h.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ClearErrorCode]
+
+******************************************************************************/
+Cudd_ErrorType
+Cudd_ReadErrorCode(
+ DdManager *dd)
+{
+ return(dd->errorCode);
+
+} /* end of Cudd_ReadErrorCode */
+
+
+/**Function********************************************************************
+
+ Synopsis [Clear the error code of a manager.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadErrorCode]
+
+******************************************************************************/
+void
+Cudd_ClearErrorCode(
+ DdManager *dd)
+{
+ dd->errorCode = CUDD_NO_ERROR;
+
+} /* end of Cudd_ClearErrorCode */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the stdout of a manager.]
+
+ Description [Reads the stdout of a manager. This is the file pointer to
+ which messages normally going to stdout are written. It is initialized
+ to stdout. Cudd_SetStdout allows the application to redirect it.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetStdout Cudd_ReadStderr]
+
+******************************************************************************/
+FILE *
+Cudd_ReadStdout(
+ DdManager *dd)
+{
+ return(dd->out);
+
+} /* end of Cudd_ReadStdout */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the stdout of a manager.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadStdout Cudd_SetStderr]
+
+******************************************************************************/
+void
+Cudd_SetStdout(
+ DdManager *dd,
+ FILE *fp)
+{
+ dd->out = fp;
+
+} /* end of Cudd_SetStdout */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the stderr of a manager.]
+
+ Description [Reads the stderr of a manager. This is the file pointer to
+ which messages normally going to stderr are written. It is initialized
+ to stderr. Cudd_SetStderr allows the application to redirect it.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetStderr Cudd_ReadStdout]
+
+******************************************************************************/
+FILE *
+Cudd_ReadStderr(
+ DdManager *dd)
+{
+ return(dd->err);
+
+} /* end of Cudd_ReadStderr */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the stderr of a manager.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadStderr Cudd_SetStdout]
+
+******************************************************************************/
+void
+Cudd_SetStderr(
+ DdManager *dd,
+ FILE *fp)
+{
+ dd->err = fp;
+
+} /* end of Cudd_SetStderr */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the threshold for the next dynamic reordering.]
+
+ Description [Returns the threshold for the next dynamic reordering.
+ The threshold is in terms of number of nodes and is in effect only
+ if reordering is enabled. The count does not include the dead nodes,
+ unless the countDead parameter of the manager has been changed from
+ its default setting.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SetNextReordering]
+
+******************************************************************************/
+unsigned int
+Cudd_ReadNextReordering(
+ DdManager *dd)
+{
+ return(dd->nextDyn);
+
+} /* end of Cudd_ReadNextReordering */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the threshold for the next dynamic reordering.]
+
+ Description [Sets the threshold for the next dynamic reordering.
+ The threshold is in terms of number of nodes and is in effect only
+ if reordering is enabled. The count does not include the dead nodes,
+ unless the countDead parameter of the manager has been changed from
+ its default setting.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ReadNextReordering]
+
+******************************************************************************/
+void
+Cudd_SetNextReordering(
+ DdManager *dd,
+ unsigned int next)
+{
+ dd->nextDyn = next;
+
+} /* end of Cudd_SetNextReordering */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the number of elementary reordering steps.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+double
+Cudd_ReadSwapSteps(
+ DdManager *dd)
+{
+#ifdef DD_COUNT
+ return(dd->swapSteps);
+#else
+ return(-1);
+#endif
+
+} /* end of Cudd_ReadSwapSteps */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the maximum allowed number of live nodes.]
+
+ Description [Reads the maximum allowed number of live nodes. When this
+ number is exceeded, the package returns NULL.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_SetMaxLive]
+
+******************************************************************************/
+unsigned int
+Cudd_ReadMaxLive(
+ DdManager *dd)
+{
+ return(dd->maxLive);
+
+} /* end of Cudd_ReadMaxLive */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the maximum allowed number of live nodes.]
+
+ Description [Sets the maximum allowed number of live nodes. When this
+ number is exceeded, the package returns NULL.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_ReadMaxLive]
+
+******************************************************************************/
+void
+Cudd_SetMaxLive(
+ DdManager *dd,
+ unsigned int maxLive)
+{
+ dd->maxLive = maxLive;
+
+} /* end of Cudd_SetMaxLive */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads the maximum allowed memory.]
+
+ Description [Reads the maximum allowed memory. When this
+ number is exceeded, the package returns NULL.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_SetMaxMemory]
+
+******************************************************************************/
+long
+Cudd_ReadMaxMemory(
+ DdManager *dd)
+{
+ return(dd->maxmemhard);
+
+} /* end of Cudd_ReadMaxMemory */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets the maximum allowed memory.]
+
+ Description [Sets the maximum allowed memory. When this
+ number is exceeded, the package returns NULL.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_ReadMaxMemory]
+
+******************************************************************************/
+void
+Cudd_SetMaxMemory(
+ DdManager *dd,
+ long maxMemory)
+{
+ dd->maxmemhard = maxMemory;
+
+} /* end of Cudd_SetMaxMemory */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prevents sifting of a variable.]
+
+ Description [This function sets a flag to prevent sifting of a
+ variable. Returns 1 if successful; 0 otherwise (i.e., invalid
+ variable index).]
+
+ SideEffects [Changes the "bindVar" flag in DdSubtable.]
+
+ SeeAlso [Cudd_bddUnbindVar]
+
+******************************************************************************/
+int
+Cudd_bddBindVar(
+ DdManager *dd /* manager */,
+ int index /* variable index */)
+{
+ if (index >= dd->size || index < 0) return(0);
+ dd->subtables[dd->perm[index]].bindVar = 1;
+ return(1);
+
+} /* end of Cudd_bddBindVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Allows the sifting of a variable.]
+
+ Description [This function resets the flag that prevents the sifting
+ of a variable. In successive variable reorderings, the variable will
+ NOT be skipped, that is, sifted. Initially all variables can be
+ sifted. It is necessary to call this function only to re-enable
+ sifting after a call to Cudd_bddBindVar. Returns 1 if successful; 0
+ otherwise (i.e., invalid variable index).]
+
+ SideEffects [Changes the "bindVar" flag in DdSubtable.]
+
+ SeeAlso [Cudd_bddBindVar]
+
+******************************************************************************/
+int
+Cudd_bddUnbindVar(
+ DdManager *dd /* manager */,
+ int index /* variable index */)
+{
+ if (index >= dd->size || index < 0) return(0);
+ dd->subtables[dd->perm[index]].bindVar = 0;
+ return(1);
+
+} /* end of Cudd_bddUnbindVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Tells whether a variable can be sifted.]
+
+ Description [This function returns 1 if a variable is enabled for
+ sifting. Initially all variables can be sifted. This function returns
+ 0 only if there has been a previous call to Cudd_bddBindVar for that
+ variable not followed by a call to Cudd_bddUnbindVar. The function returns
+ 0 also in the case in which the index of the variable is out of bounds.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_bddBindVar Cudd_bddUnbindVar]
+
+******************************************************************************/
+int
+Cudd_bddVarIsBound(
+ DdManager *dd /* manager */,
+ int index /* variable index */)
+{
+ if (index >= dd->size || index < 0) return(0);
+ return(dd->subtables[dd->perm[index]].bindVar);
+
+} /* end of Cudd_bddVarIsBound */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets a variable type to primary input.]
+
+ Description [Sets a variable type to primary input. The variable type is
+ used by lazy sifting. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [modifies the manager]
+
+ SeeAlso [Cudd_bddSetPsVar Cudd_bddSetNsVar Cudd_bddIsPiVar]
+
+******************************************************************************/
+int
+Cudd_bddSetPiVar(
+ DdManager *dd /* manager */,
+ int index /* variable index */)
+{
+ if (index >= dd->size || index < 0) return (0);
+ dd->subtables[dd->perm[index]].varType = CUDD_VAR_PRIMARY_INPUT;
+ return(1);
+
+} /* end of Cudd_bddSetPiVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets a variable type to present state.]
+
+ Description [Sets a variable type to present state. The variable type is
+ used by lazy sifting. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [modifies the manager]
+
+ SeeAlso [Cudd_bddSetPiVar Cudd_bddSetNsVar Cudd_bddIsPsVar]
+
+******************************************************************************/
+int
+Cudd_bddSetPsVar(
+ DdManager *dd /* manager */,
+ int index /* variable index */)
+{
+ if (index >= dd->size || index < 0) return (0);
+ dd->subtables[dd->perm[index]].varType = CUDD_VAR_PRESENT_STATE;
+ return(1);
+
+} /* end of Cudd_bddSetPsVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets a variable type to next state.]
+
+ Description [Sets a variable type to next state. The variable type is
+ used by lazy sifting. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [modifies the manager]
+
+ SeeAlso [Cudd_bddSetPiVar Cudd_bddSetPsVar Cudd_bddIsNsVar]
+
+******************************************************************************/
+int
+Cudd_bddSetNsVar(
+ DdManager *dd /* manager */,
+ int index /* variable index */)
+{
+ if (index >= dd->size || index < 0) return (0);
+ dd->subtables[dd->perm[index]].varType = CUDD_VAR_NEXT_STATE;
+ return(1);
+
+} /* end of Cudd_bddSetNsVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether a variable is primary input.]
+
+ Description [Checks whether a variable is primary input. Returns 1 if
+ the variable's type is primary input; 0 if the variable exists but is
+ not a primary input; -1 if the variable does not exist.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_bddSetPiVar Cudd_bddIsPsVar Cudd_bddIsNsVar]
+
+******************************************************************************/
+int
+Cudd_bddIsPiVar(
+ DdManager *dd /* manager */,
+ int index /* variable index */)
+{
+ if (index >= dd->size || index < 0) return -1;
+ return (dd->subtables[dd->perm[index]].varType == CUDD_VAR_PRIMARY_INPUT);
+
+} /* end of Cudd_bddIsPiVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether a variable is present state.]
+
+ Description [Checks whether a variable is present state. Returns 1 if
+ the variable's type is present state; 0 if the variable exists but is
+ not a present state; -1 if the variable does not exist.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_bddSetPsVar Cudd_bddIsPiVar Cudd_bddIsNsVar]
+
+******************************************************************************/
+int
+Cudd_bddIsPsVar(
+ DdManager *dd,
+ int index)
+{
+ if (index >= dd->size || index < 0) return -1;
+ return (dd->subtables[dd->perm[index]].varType == CUDD_VAR_PRESENT_STATE);
+
+} /* end of Cudd_bddIsPsVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether a variable is next state.]
+
+ Description [Checks whether a variable is next state. Returns 1 if
+ the variable's type is present state; 0 if the variable exists but is
+ not a present state; -1 if the variable does not exist.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_bddSetNsVar Cudd_bddIsPiVar Cudd_bddIsPsVar]
+
+******************************************************************************/
+int
+Cudd_bddIsNsVar(
+ DdManager *dd,
+ int index)
+{
+ if (index >= dd->size || index < 0) return -1;
+ return (dd->subtables[dd->perm[index]].varType == CUDD_VAR_NEXT_STATE);
+
+} /* end of Cudd_bddIsNsVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets a corresponding pair index for a given index.]
+
+ Description [Sets a corresponding pair index for a given index.
+ These pair indices are present and next state variable. Returns 1 if
+ successful; 0 otherwise.]
+
+ SideEffects [modifies the manager]
+
+ SeeAlso [Cudd_bddReadPairIndex]
+
+******************************************************************************/
+int
+Cudd_bddSetPairIndex(
+ DdManager *dd /* manager */,
+ int index /* variable index */,
+ int pairIndex /* corresponding variable index */)
+{
+ if (index >= dd->size || index < 0) return(0);
+ dd->subtables[dd->perm[index]].pairIndex = pairIndex;
+ return(1);
+
+} /* end of Cudd_bddSetPairIndex */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads a corresponding pair index for a given index.]
+
+ Description [Reads a corresponding pair index for a given index.
+ These pair indices are present and next state variable. Returns the
+ corresponding variable index if the variable exists; -1 otherwise.]
+
+ SideEffects [modifies the manager]
+
+ SeeAlso [Cudd_bddSetPairIndex]
+
+******************************************************************************/
+int
+Cudd_bddReadPairIndex(
+ DdManager *dd,
+ int index)
+{
+ if (index >= dd->size || index < 0) return -1;
+ return dd->subtables[dd->perm[index]].pairIndex;
+
+} /* end of Cudd_bddReadPairIndex */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets a variable to be grouped.]
+
+ Description [Sets a variable to be grouped. This function is used for
+ lazy sifting. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [modifies the manager]
+
+ SeeAlso [Cudd_bddSetVarHardGroup Cudd_bddResetVarToBeGrouped]
+
+******************************************************************************/
+int
+Cudd_bddSetVarToBeGrouped(
+ DdManager *dd,
+ int index)
+{
+ if (index >= dd->size || index < 0) return(0);
+ if (dd->subtables[dd->perm[index]].varToBeGrouped <= CUDD_LAZY_SOFT_GROUP) {
+ dd->subtables[dd->perm[index]].varToBeGrouped = CUDD_LAZY_SOFT_GROUP;
+ }
+ return(1);
+
+} /* end of Cudd_bddSetVarToBeGrouped */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets a variable to be a hard group.]
+
+ Description [Sets a variable to be a hard group. This function is used
+ for lazy sifting. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [modifies the manager]
+
+ SeeAlso [Cudd_bddSetVarToBeGrouped Cudd_bddResetVarToBeGrouped
+ Cudd_bddIsVarHardGroup]
+
+******************************************************************************/
+int
+Cudd_bddSetVarHardGroup(
+ DdManager *dd,
+ int index)
+{
+ if (index >= dd->size || index < 0) return(0);
+ dd->subtables[dd->perm[index]].varToBeGrouped = CUDD_LAZY_HARD_GROUP;
+ return(1);
+
+} /* end of Cudd_bddSetVarHardGrouped */
+
+
+/**Function********************************************************************
+
+ Synopsis [Resets a variable not to be grouped.]
+
+ Description [Resets a variable not to be grouped. This function is
+ used for lazy sifting. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [modifies the manager]
+
+ SeeAlso [Cudd_bddSetVarToBeGrouped Cudd_bddSetVarHardGroup]
+
+******************************************************************************/
+int
+Cudd_bddResetVarToBeGrouped(
+ DdManager *dd,
+ int index)
+{
+ if (index >= dd->size || index < 0) return(0);
+ if (dd->subtables[dd->perm[index]].varToBeGrouped <=
+ CUDD_LAZY_SOFT_GROUP) {
+ dd->subtables[dd->perm[index]].varToBeGrouped = CUDD_LAZY_NONE;
+ }
+ return(1);
+
+} /* end of Cudd_bddResetVarToBeGrouped */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether a variable is set to be grouped.]
+
+ Description [Checks whether a variable is set to be grouped. This
+ function is used for lazy sifting.]
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+Cudd_bddIsVarToBeGrouped(
+ DdManager *dd,
+ int index)
+{
+ if (index >= dd->size || index < 0) return(-1);
+ if (dd->subtables[dd->perm[index]].varToBeGrouped == CUDD_LAZY_UNGROUP)
+ return(0);
+ else
+ return(dd->subtables[dd->perm[index]].varToBeGrouped);
+
+} /* end of Cudd_bddIsVarToBeGrouped */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets a variable to be ungrouped.]
+
+ Description [Sets a variable to be ungrouped. This function is used
+ for lazy sifting. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [modifies the manager]
+
+ SeeAlso [Cudd_bddIsVarToBeUngrouped]
+
+******************************************************************************/
+int
+Cudd_bddSetVarToBeUngrouped(
+ DdManager *dd,
+ int index)
+{
+ if (index >= dd->size || index < 0) return(0);
+ dd->subtables[dd->perm[index]].varToBeGrouped = CUDD_LAZY_UNGROUP;
+ return(1);
+
+} /* end of Cudd_bddSetVarToBeGrouped */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether a variable is set to be ungrouped.]
+
+ Description [Checks whether a variable is set to be ungrouped. This
+ function is used for lazy sifting. Returns 1 if the variable is marked
+ to be ungrouped; 0 if the variable exists, but it is not marked to be
+ ungrouped; -1 if the variable does not exist.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_bddSetVarToBeUngrouped]
+
+******************************************************************************/
+int
+Cudd_bddIsVarToBeUngrouped(
+ DdManager *dd,
+ int index)
+{
+ if (index >= dd->size || index < 0) return(-1);
+ return dd->subtables[dd->perm[index]].varToBeGrouped == CUDD_LAZY_UNGROUP;
+
+} /* end of Cudd_bddIsVarToBeGrouped */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether a variable is set to be in a hard group.]
+
+ Description [Checks whether a variable is set to be in a hard group. This
+ function is used for lazy sifting. Returns 1 if the variable is marked
+ to be in a hard group; 0 if the variable exists, but it is not marked to be
+ in a hard group; -1 if the variable does not exist.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_bddSetVarHardGroup]
+
+******************************************************************************/
+int
+Cudd_bddIsVarHardGroup(
+ DdManager *dd,
+ int index)
+{
+ if (index >= dd->size || index < 0) return(-1);
+ if (dd->subtables[dd->perm[index]].varToBeGrouped == CUDD_LAZY_HARD_GROUP)
+ return(1);
+ return(0);
+
+} /* end of Cudd_bddIsVarToBeGrouped */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Fixes a variable group tree.]
+
+ Description []
+
+ SideEffects [Changes the variable group tree.]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+fixVarTree(
+ MtrNode * treenode,
+ int * perm,
+ int size)
+{
+ treenode->index = treenode->low;
+ treenode->low = ((int) treenode->index < size) ?
+ perm[treenode->index] : treenode->index;
+ if (treenode->child != NULL)
+ fixVarTree(treenode->child, perm, size);
+ if (treenode->younger != NULL)
+ fixVarTree(treenode->younger, perm, size);
+ return;
+
+} /* end of fixVarTree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Adds multiplicity groups to a ZDD variable group tree.]
+
+ Description [Adds multiplicity groups to a ZDD variable group tree.
+ Returns 1 if successful; 0 otherwise. This function creates the groups
+ for set of ZDD variables (whose cardinality is given by parameter
+ multiplicity) that are created for each BDD variable in
+ Cudd_zddVarsFromBddVars. The crux of the matter is to determine the index
+ each new group. (The index of the first variable in the group.)
+ We first build all the groups for the children of a node, and then deal
+ with the ZDD variables that are directly attached to the node. The problem
+ for these is that the tree itself does not provide information on their
+ position inside the group. While we deal with the children of the node,
+ therefore, we keep track of all the positions they occupy. The remaining
+ positions in the tree can be freely used. Also, we keep track of all the
+ variables placed in the children. All the remaining variables are directly
+ attached to the group. We can then place any pair of variables not yet
+ grouped in any pair of available positions in the node.]
+
+ SideEffects [Changes the variable group tree.]
+
+ SeeAlso [Cudd_zddVarsFromBddVars]
+
+******************************************************************************/
+static int
+addMultiplicityGroups(
+ DdManager *dd /* manager */,
+ MtrNode *treenode /* current tree node */,
+ int multiplicity /* how many ZDD vars per BDD var */,
+ char *vmask /* variable pairs for which a group has been already built */,
+ char *lmask /* levels for which a group has already been built*/)
+{
+ int startV, stopV, startL;
+ int i, j;
+ MtrNode *auxnode = treenode;
+
+ while (auxnode != NULL) {
+ if (auxnode->child != NULL) {
+ addMultiplicityGroups(dd,auxnode->child,multiplicity,vmask,lmask);
+ }
+ /* Build remaining groups. */
+ startV = dd->permZ[auxnode->index] / multiplicity;
+ startL = auxnode->low / multiplicity;
+ stopV = startV + auxnode->size / multiplicity;
+ /* Walk down vmask starting at startV and build missing groups. */
+ for (i = startV, j = startL; i < stopV; i++) {
+ if (vmask[i] == 0) {
+ MtrNode *node;
+ while (lmask[j] == 1) j++;
+ node = Mtr_MakeGroup(auxnode, j * multiplicity, multiplicity,
+ MTR_FIXED);
+ if (node == NULL) {
+ return(0);
+ }
+ node->index = dd->invpermZ[i * multiplicity];
+ vmask[i] = 1;
+ lmask[j] = 1;
+ }
+ }
+ auxnode = auxnode->younger;
+ }
+ return(1);
+
+} /* end of addMultiplicityGroups */
+
diff --git a/src/bdd/cudd/cuddAddAbs.c b/src/bdd/cudd/cuddAddAbs.c
new file mode 100644
index 00000000..27039908
--- /dev/null
+++ b/src/bdd/cudd/cuddAddAbs.c
@@ -0,0 +1,566 @@
+/**CFile***********************************************************************
+
+ FileName [cuddAddAbs.c]
+
+ PackageName [cudd]
+
+ Synopsis [Quantification functions for ADDs.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_addExistAbstract()
+ <li> Cudd_addUnivAbstract()
+ <li> Cudd_addOrAbstract()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddAddExistAbstractRecur()
+ <li> cuddAddUnivAbstractRecur()
+ <li> cuddAddOrAbstractRecur()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> addCheckPositiveCube()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddAddAbs.c,v 1.1.1.1 2003/02/24 22:23:50 wjiang Exp $";
+#endif
+
+static DdNode *two;
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int addCheckPositiveCube ARGS((DdManager *manager, DdNode *cube));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Existentially Abstracts all the variables in cube from f.]
+
+ Description [Abstracts all the variables in cube from f by summing
+ over all possible values taken by the variables. Returns the
+ abstracted ADD.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addUnivAbstract Cudd_bddExistAbstract
+ Cudd_addOrAbstract]
+
+******************************************************************************/
+DdNode *
+Cudd_addExistAbstract(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * cube)
+{
+ DdNode *res;
+
+ two = cuddUniqueConst(manager,(CUDD_VALUE_TYPE) 2);
+ if (two == NULL) return(NULL);
+ cuddRef(two);
+
+ if (addCheckPositiveCube(manager, cube) == 0) {
+ (void) fprintf(manager->err,"Error: Can only abstract cubes");
+ return(NULL);
+ }
+
+ do {
+ manager->reordered = 0;
+ res = cuddAddExistAbstractRecur(manager, f, cube);
+ } while (manager->reordered == 1);
+
+ if (res == NULL) {
+ Cudd_RecursiveDeref(manager,two);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(manager,two);
+ cuddDeref(res);
+
+ return(res);
+
+} /* end of Cudd_addExistAbstract */
+
+
+/**Function********************************************************************
+
+ Synopsis [Universally Abstracts all the variables in cube from f.]
+
+ Description [Abstracts all the variables in cube from f by taking
+ the product over all possible values taken by the variable. Returns
+ the abstracted ADD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addExistAbstract Cudd_bddUnivAbstract
+ Cudd_addOrAbstract]
+
+******************************************************************************/
+DdNode *
+Cudd_addUnivAbstract(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * cube)
+{
+ DdNode *res;
+
+ if (addCheckPositiveCube(manager, cube) == 0) {
+ (void) fprintf(manager->err,"Error: Can only abstract cubes");
+ return(NULL);
+ }
+
+ do {
+ manager->reordered = 0;
+ res = cuddAddUnivAbstractRecur(manager, f, cube);
+ } while (manager->reordered == 1);
+
+ return(res);
+
+} /* end of Cudd_addUnivAbstract */
+
+
+/**Function********************************************************************
+
+ Synopsis [Disjunctively abstracts all the variables in cube from the
+ 0-1 ADD f.]
+
+ Description [Abstracts all the variables in cube from the 0-1 ADD f
+ by taking the disjunction over all possible values taken by the
+ variables. Returns the abstracted ADD if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addUnivAbstract Cudd_addExistAbstract]
+
+******************************************************************************/
+DdNode *
+Cudd_addOrAbstract(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * cube)
+{
+ DdNode *res;
+
+ if (addCheckPositiveCube(manager, cube) == 0) {
+ (void) fprintf(manager->err,"Error: Can only abstract cubes");
+ return(NULL);
+ }
+
+ do {
+ manager->reordered = 0;
+ res = cuddAddOrAbstractRecur(manager, f, cube);
+ } while (manager->reordered == 1);
+ return(res);
+
+} /* end of Cudd_addOrAbstract */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addExistAbstract.]
+
+ Description [Performs the recursive step of Cudd_addExistAbstract.
+ Returns the ADD obtained by abstracting the variables of cube from f,
+ if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+cuddAddExistAbstractRecur(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * cube)
+{
+ DdNode *T, *E, *res, *res1, *res2, *zero;
+
+ statLine(manager);
+ zero = DD_ZERO(manager);
+
+ /* Cube is guaranteed to be a cube at this point. */
+ if (f == zero || cuddIsConstant(cube)) {
+ return(f);
+ }
+
+ /* Abstract a variable that does not appear in f => multiply by 2. */
+ if (cuddI(manager,f->index) > cuddI(manager,cube->index)) {
+ res1 = cuddAddExistAbstractRecur(manager, f, cuddT(cube));
+ if (res1 == NULL) return(NULL);
+ cuddRef(res1);
+ /* Use the "internal" procedure to be alerted in case of
+ ** dynamic reordering. If dynamic reordering occurs, we
+ ** have to abort the entire abstraction.
+ */
+ res = cuddAddApplyRecur(manager,Cudd_addTimes,res1,two);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(manager,res1);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(manager,res1);
+ cuddDeref(res);
+ return(res);
+ }
+
+ if ((res = cuddCacheLookup2(manager, Cudd_addExistAbstract, f, cube)) != NULL) {
+ return(res);
+ }
+
+ T = cuddT(f);
+ E = cuddE(f);
+
+ /* If the two indices are the same, so are their levels. */
+ if (f->index == cube->index) {
+ res1 = cuddAddExistAbstractRecur(manager, T, cuddT(cube));
+ if (res1 == NULL) return(NULL);
+ cuddRef(res1);
+ res2 = cuddAddExistAbstractRecur(manager, E, cuddT(cube));
+ if (res2 == NULL) {
+ Cudd_RecursiveDeref(manager,res1);
+ return(NULL);
+ }
+ cuddRef(res2);
+ res = cuddAddApplyRecur(manager, Cudd_addPlus, res1, res2);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(manager,res1);
+ Cudd_RecursiveDeref(manager,res2);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(manager,res1);
+ Cudd_RecursiveDeref(manager,res2);
+ cuddCacheInsert2(manager, Cudd_addExistAbstract, f, cube, res);
+ cuddDeref(res);
+ return(res);
+ } else { /* if (cuddI(manager,f->index) < cuddI(manager,cube->index)) */
+ res1 = cuddAddExistAbstractRecur(manager, T, cube);
+ if (res1 == NULL) return(NULL);
+ cuddRef(res1);
+ res2 = cuddAddExistAbstractRecur(manager, E, cube);
+ if (res2 == NULL) {
+ Cudd_RecursiveDeref(manager,res1);
+ return(NULL);
+ }
+ cuddRef(res2);
+ res = (res1 == res2) ? res1 :
+ cuddUniqueInter(manager, (int) f->index, res1, res2);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(manager,res1);
+ Cudd_RecursiveDeref(manager,res2);
+ return(NULL);
+ }
+ cuddDeref(res1);
+ cuddDeref(res2);
+ cuddCacheInsert2(manager, Cudd_addExistAbstract, f, cube, res);
+ return(res);
+ }
+
+} /* end of cuddAddExistAbstractRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addUnivAbstract.]
+
+ Description [Performs the recursive step of Cudd_addUnivAbstract.
+ Returns the ADD obtained by abstracting the variables of cube from f,
+ if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+cuddAddUnivAbstractRecur(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * cube)
+{
+ DdNode *T, *E, *res, *res1, *res2, *one, *zero;
+
+ statLine(manager);
+ one = DD_ONE(manager);
+ zero = DD_ZERO(manager);
+
+ /* Cube is guaranteed to be a cube at this point.
+ ** zero and one are the only constatnts c such that c*c=c.
+ */
+ if (f == zero || f == one || cube == one) {
+ return(f);
+ }
+
+ /* Abstract a variable that does not appear in f. */
+ if (cuddI(manager,f->index) > cuddI(manager,cube->index)) {
+ res1 = cuddAddUnivAbstractRecur(manager, f, cuddT(cube));
+ if (res1 == NULL) return(NULL);
+ cuddRef(res1);
+ /* Use the "internal" procedure to be alerted in case of
+ ** dynamic reordering. If dynamic reordering occurs, we
+ ** have to abort the entire abstraction.
+ */
+ res = cuddAddApplyRecur(manager, Cudd_addTimes, res1, res1);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(manager,res1);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(manager,res1);
+ cuddDeref(res);
+ return(res);
+ }
+
+ if ((res = cuddCacheLookup2(manager, Cudd_addUnivAbstract, f, cube)) != NULL) {
+ return(res);
+ }
+
+ T = cuddT(f);
+ E = cuddE(f);
+
+ /* If the two indices are the same, so are their levels. */
+ if (f->index == cube->index) {
+ res1 = cuddAddUnivAbstractRecur(manager, T, cuddT(cube));
+ if (res1 == NULL) return(NULL);
+ cuddRef(res1);
+ res2 = cuddAddUnivAbstractRecur(manager, E, cuddT(cube));
+ if (res2 == NULL) {
+ Cudd_RecursiveDeref(manager,res1);
+ return(NULL);
+ }
+ cuddRef(res2);
+ res = cuddAddApplyRecur(manager, Cudd_addTimes, res1, res2);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(manager,res1);
+ Cudd_RecursiveDeref(manager,res2);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(manager,res1);
+ Cudd_RecursiveDeref(manager,res2);
+ cuddCacheInsert2(manager, Cudd_addUnivAbstract, f, cube, res);
+ cuddDeref(res);
+ return(res);
+ } else { /* if (cuddI(manager,f->index) < cuddI(manager,cube->index)) */
+ res1 = cuddAddUnivAbstractRecur(manager, T, cube);
+ if (res1 == NULL) return(NULL);
+ cuddRef(res1);
+ res2 = cuddAddUnivAbstractRecur(manager, E, cube);
+ if (res2 == NULL) {
+ Cudd_RecursiveDeref(manager,res1);
+ return(NULL);
+ }
+ cuddRef(res2);
+ res = (res1 == res2) ? res1 :
+ cuddUniqueInter(manager, (int) f->index, res1, res2);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(manager,res1);
+ Cudd_RecursiveDeref(manager,res2);
+ return(NULL);
+ }
+ cuddDeref(res1);
+ cuddDeref(res2);
+ cuddCacheInsert2(manager, Cudd_addUnivAbstract, f, cube, res);
+ return(res);
+ }
+
+} /* end of cuddAddUnivAbstractRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addOrAbstract.]
+
+ Description [Performs the recursive step of Cudd_addOrAbstract.
+ Returns the ADD obtained by abstracting the variables of cube from f,
+ if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+cuddAddOrAbstractRecur(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * cube)
+{
+ DdNode *T, *E, *res, *res1, *res2, *one;
+
+ statLine(manager);
+ one = DD_ONE(manager);
+
+ /* Cube is guaranteed to be a cube at this point. */
+ if (cuddIsConstant(f) || cube == one) {
+ return(f);
+ }
+
+ /* Abstract a variable that does not appear in f. */
+ if (cuddI(manager,f->index) > cuddI(manager,cube->index)) {
+ res1 = cuddAddOrAbstractRecur(manager, f, cuddT(cube));
+ if (res1 == NULL) return(NULL);
+ cuddRef(res1);
+ /* Use the "internal" procedure to be alerted in case of
+ ** dynamic reordering. If dynamic reordering occurs, we
+ ** have to abort the entire abstraction.
+ */
+ res = cuddAddApplyRecur(manager, Cudd_addOr, res1, res1);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(manager,res1);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(manager,res1);
+ cuddDeref(res);
+ return(res);
+ }
+
+ if ((res = cuddCacheLookup2(manager, Cudd_addOrAbstract, f, cube)) != NULL) {
+ return(res);
+ }
+
+ T = cuddT(f);
+ E = cuddE(f);
+
+ /* If the two indices are the same, so are their levels. */
+ if (f->index == cube->index) {
+ res1 = cuddAddOrAbstractRecur(manager, T, cuddT(cube));
+ if (res1 == NULL) return(NULL);
+ cuddRef(res1);
+ if (res1 != one) {
+ res2 = cuddAddOrAbstractRecur(manager, E, cuddT(cube));
+ if (res2 == NULL) {
+ Cudd_RecursiveDeref(manager,res1);
+ return(NULL);
+ }
+ cuddRef(res2);
+ res = cuddAddApplyRecur(manager, Cudd_addOr, res1, res2);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(manager,res1);
+ Cudd_RecursiveDeref(manager,res2);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(manager,res1);
+ Cudd_RecursiveDeref(manager,res2);
+ } else {
+ res = res1;
+ }
+ cuddCacheInsert2(manager, Cudd_addOrAbstract, f, cube, res);
+ cuddDeref(res);
+ return(res);
+ } else { /* if (cuddI(manager,f->index) < cuddI(manager,cube->index)) */
+ res1 = cuddAddOrAbstractRecur(manager, T, cube);
+ if (res1 == NULL) return(NULL);
+ cuddRef(res1);
+ res2 = cuddAddOrAbstractRecur(manager, E, cube);
+ if (res2 == NULL) {
+ Cudd_RecursiveDeref(manager,res1);
+ return(NULL);
+ }
+ cuddRef(res2);
+ res = (res1 == res2) ? res1 :
+ cuddUniqueInter(manager, (int) f->index, res1, res2);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(manager,res1);
+ Cudd_RecursiveDeref(manager,res2);
+ return(NULL);
+ }
+ cuddDeref(res1);
+ cuddDeref(res2);
+ cuddCacheInsert2(manager, Cudd_addOrAbstract, f, cube, res);
+ return(res);
+ }
+
+} /* end of cuddAddOrAbstractRecur */
+
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether cube is an ADD representing the product
+ of positive literals.]
+
+ Description [Checks whether cube is an ADD representing the product of
+ positive literals. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+addCheckPositiveCube(
+ DdManager * manager,
+ DdNode * cube)
+{
+ if (Cudd_IsComplement(cube)) return(0);
+ if (cube == DD_ONE(manager)) return(1);
+ if (cuddIsConstant(cube)) return(0);
+ if (cuddE(cube) == DD_ZERO(manager)) {
+ return(addCheckPositiveCube(manager, cuddT(cube)));
+ }
+ return(0);
+
+} /* end of addCheckPositiveCube */
+
diff --git a/src/bdd/cudd/cuddAddApply.c b/src/bdd/cudd/cuddAddApply.c
new file mode 100644
index 00000000..67649913
--- /dev/null
+++ b/src/bdd/cudd/cuddAddApply.c
@@ -0,0 +1,917 @@
+/**CFile***********************************************************************
+
+ FileName [cuddAddApply.c]
+
+ PackageName [cudd]
+
+ Synopsis [Apply functions for ADDs and their operators.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_addApply()
+ <li> Cudd_addMonadicApply()
+ <li> Cudd_addPlus()
+ <li> Cudd_addTimes()
+ <li> Cudd_addThreshold()
+ <li> Cudd_addSetNZ()
+ <li> Cudd_addDivide()
+ <li> Cudd_addMinus()
+ <li> Cudd_addMinimum()
+ <li> Cudd_addMaximum()
+ <li> Cudd_addOneZeroMaximum()
+ <li> Cudd_addDiff()
+ <li> Cudd_addAgreement()
+ <li> Cudd_addOr()
+ <li> Cudd_addNand()
+ <li> Cudd_addNor()
+ <li> Cudd_addXor()
+ <li> Cudd_addXnor()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddAddApplyRecur()
+ <li> cuddAddMonadicApplyRecur()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at Boulder.
+ The University of Colorado at Boulder makes no warranty about the
+ suitability of this software for any purpose. It is presented on an
+ AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddAddApply.c,v 1.1.1.1 2003/02/24 22:23:50 wjiang Exp $";
+#endif
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Applies op to the corresponding discriminants of f and g.]
+
+ Description [Applies op to the corresponding discriminants of f and g.
+ Returns a pointer to the result if succssful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addMonadicApply Cudd_addPlus Cudd_addTimes
+ Cudd_addThreshold Cudd_addSetNZ Cudd_addDivide Cudd_addMinus Cudd_addMinimum
+ Cudd_addMaximum Cudd_addOneZeroMaximum Cudd_addDiff Cudd_addAgreement
+ Cudd_addOr Cudd_addNand Cudd_addNor Cudd_addXor Cudd_addXnor]
+
+******************************************************************************/
+DdNode *
+Cudd_addApply(
+ DdManager * dd,
+ DdNode * (*op)(DdManager *, DdNode **, DdNode **),
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddAddApplyRecur(dd,op,f,g);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_addApply */
+
+
+/**Function********************************************************************
+
+ Synopsis [Integer and floating point addition.]
+
+ Description [Integer and floating point addition. Returns NULL if not
+ a terminal case; f+g otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addPlus(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+ DdNode *res;
+ DdNode *F, *G;
+ CUDD_VALUE_TYPE value;
+
+ F = *f; G = *g;
+ if (F == DD_ZERO(dd)) return(G);
+ if (G == DD_ZERO(dd)) return(F);
+ if (cuddIsConstant(F) && cuddIsConstant(G)) {
+ value = cuddV(F)+cuddV(G);
+ res = cuddUniqueConst(dd,value);
+ return(res);
+ }
+ if (F > G) { /* swap f and g */
+ *f = G;
+ *g = F;
+ }
+ return(NULL);
+
+} /* end of Cudd_addPlus */
+
+
+/**Function********************************************************************
+
+ Synopsis [Integer and floating point multiplication.]
+
+ Description [Integer and floating point multiplication. Returns NULL
+ if not a terminal case; f * g otherwise. This function can be used also
+ to take the AND of two 0-1 ADDs.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addTimes(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+ DdNode *res;
+ DdNode *F, *G;
+ CUDD_VALUE_TYPE value;
+
+ F = *f; G = *g;
+ if (F == DD_ZERO(dd) || G == DD_ZERO(dd)) return(DD_ZERO(dd));
+ if (F == DD_ONE(dd)) return(G);
+ if (G == DD_ONE(dd)) return(F);
+ if (cuddIsConstant(F) && cuddIsConstant(G)) {
+ value = cuddV(F)*cuddV(G);
+ res = cuddUniqueConst(dd,value);
+ return(res);
+ }
+ if (F > G) { /* swap f and g */
+ *f = G;
+ *g = F;
+ }
+ return(NULL);
+
+} /* end of Cudd_addTimes */
+
+
+/**Function********************************************************************
+
+ Synopsis [f if f&gt;=g; 0 if f&lt;g.]
+
+ Description [Threshold operator for Apply (f if f &gt;=g; 0 if f&lt;g).
+ Returns NULL if not a terminal case; f op g otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addThreshold(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+ DdNode *F, *G;
+
+ F = *f; G = *g;
+ if (F == G || F == DD_PLUS_INFINITY(dd)) return(F);
+ if (cuddIsConstant(F) && cuddIsConstant(G)) {
+ if (cuddV(F) >= cuddV(G)) {
+ return(F);
+ } else {
+ return(DD_ZERO(dd));
+ }
+ }
+ return(NULL);
+
+} /* end of Cudd_addThreshold */
+
+
+/**Function********************************************************************
+
+ Synopsis [This operator sets f to the value of g wherever g != 0.]
+
+ Description [This operator sets f to the value of g wherever g != 0.
+ Returns NULL if not a terminal case; f op g otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addSetNZ(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+ DdNode *F, *G;
+
+ F = *f; G = *g;
+ if (F == G) return(F);
+ if (F == DD_ZERO(dd)) return(G);
+ if (G == DD_ZERO(dd)) return(F);
+ if (cuddIsConstant(G)) return(G);
+ return(NULL);
+
+} /* end of Cudd_addSetNZ */
+
+
+/**Function********************************************************************
+
+ Synopsis [Integer and floating point division.]
+
+ Description [Integer and floating point division. Returns NULL if not
+ a terminal case; f / g otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addDivide(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+ DdNode *res;
+ DdNode *F, *G;
+ CUDD_VALUE_TYPE value;
+
+ F = *f; G = *g;
+ /* We would like to use F == G -> F/G == 1, but F and G may
+ ** contain zeroes. */
+ if (F == DD_ZERO(dd)) return(DD_ZERO(dd));
+ if (G == DD_ONE(dd)) return(F);
+ if (cuddIsConstant(F) && cuddIsConstant(G)) {
+ value = cuddV(F)/cuddV(G);
+ res = cuddUniqueConst(dd,value);
+ return(res);
+ }
+ return(NULL);
+
+} /* end of Cudd_addDivide */
+
+
+/**Function********************************************************************
+
+ Synopsis [Integer and floating point subtraction.]
+
+ Description [Integer and floating point subtraction. Returns NULL if
+ not a terminal case; f - g otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addMinus(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+ DdNode *res;
+ DdNode *F, *G;
+ CUDD_VALUE_TYPE value;
+
+ F = *f; G = *g;
+ if (F == G) return(DD_ZERO(dd));
+ if (F == DD_ZERO(dd)) return(cuddAddNegateRecur(dd,G));
+ if (G == DD_ZERO(dd)) return(F);
+ if (cuddIsConstant(F) && cuddIsConstant(G)) {
+ value = cuddV(F)-cuddV(G);
+ res = cuddUniqueConst(dd,value);
+ return(res);
+ }
+ return(NULL);
+
+} /* end of Cudd_addMinus */
+
+
+/**Function********************************************************************
+
+ Synopsis [Integer and floating point min.]
+
+ Description [Integer and floating point min for Cudd_addApply.
+ Returns NULL if not a terminal case; min(f,g) otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addMinimum(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+ DdNode *F, *G;
+
+ F = *f; G = *g;
+ if (F == DD_PLUS_INFINITY(dd)) return(G);
+ if (G == DD_PLUS_INFINITY(dd)) return(F);
+ if (F == G) return(F);
+#if 0
+ /* These special cases probably do not pay off. */
+ if (F == DD_MINUS_INFINITY(dd)) return(F);
+ if (G == DD_MINUS_INFINITY(dd)) return(G);
+#endif
+ if (cuddIsConstant(F) && cuddIsConstant(G)) {
+ if (cuddV(F) <= cuddV(G)) {
+ return(F);
+ } else {
+ return(G);
+ }
+ }
+ if (F > G) { /* swap f and g */
+ *f = G;
+ *g = F;
+ }
+ return(NULL);
+
+} /* end of Cudd_addMinimum */
+
+
+/**Function********************************************************************
+
+ Synopsis [Integer and floating point max.]
+
+ Description [Integer and floating point max for Cudd_addApply.
+ Returns NULL if not a terminal case; max(f,g) otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addMaximum(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+ DdNode *F, *G;
+
+ F = *f; G = *g;
+ if (F == G) return(F);
+ if (F == DD_MINUS_INFINITY(dd)) return(G);
+ if (G == DD_MINUS_INFINITY(dd)) return(F);
+#if 0
+ /* These special cases probably do not pay off. */
+ if (F == DD_PLUS_INFINITY(dd)) return(F);
+ if (G == DD_PLUS_INFINITY(dd)) return(G);
+#endif
+ if (cuddIsConstant(F) && cuddIsConstant(G)) {
+ if (cuddV(F) >= cuddV(G)) {
+ return(F);
+ } else {
+ return(G);
+ }
+ }
+ if (F > G) { /* swap f and g */
+ *f = G;
+ *g = F;
+ }
+ return(NULL);
+
+} /* end of Cudd_addMaximum */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns 1 if f &gt; g and 0 otherwise.]
+
+ Description [Returns 1 if f &gt; g and 0 otherwise. Used in
+ conjunction with Cudd_addApply. Returns NULL if not a terminal
+ case.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addOneZeroMaximum(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+
+ if (*f == *g) return(DD_ZERO(dd));
+ if (*g == DD_PLUS_INFINITY(dd))
+ return DD_ZERO(dd);
+ if (cuddIsConstant(*f) && cuddIsConstant(*g)) {
+ if (cuddV(*f) > cuddV(*g)) {
+ return(DD_ONE(dd));
+ } else {
+ return(DD_ZERO(dd));
+ }
+ }
+
+ return(NULL);
+
+} /* end of Cudd_addOneZeroMaximum */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns plusinfinity if f=g; returns min(f,g) if f!=g.]
+
+ Description [Returns NULL if not a terminal case; f op g otherwise,
+ where f op g is plusinfinity if f=g; min(f,g) if f!=g.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addDiff(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+ DdNode *F, *G;
+
+ F = *f; G = *g;
+ if (F == G) return(DD_PLUS_INFINITY(dd));
+ if (F == DD_PLUS_INFINITY(dd)) return(G);
+ if (G == DD_PLUS_INFINITY(dd)) return(F);
+ if (cuddIsConstant(F) && cuddIsConstant(G)) {
+ if (cuddV(F) != cuddV(G)) {
+ if (cuddV(F) < cuddV(G)) {
+ return(F);
+ } else {
+ return(G);
+ }
+ } else {
+ return(DD_PLUS_INFINITY(dd));
+ }
+ }
+ return(NULL);
+
+} /* end of Cudd_addDiff */
+
+
+/**Function********************************************************************
+
+ Synopsis [f if f==g; background if f!=g.]
+
+ Description [Returns NULL if not a terminal case; f op g otherwise,
+ where f op g is f if f==g; background if f!=g.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addAgreement(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+ DdNode *F, *G;
+
+ F = *f; G = *g;
+ if (F == G) return(F);
+ if (F == dd->background) return(F);
+ if (G == dd->background) return(G);
+ if (cuddIsConstant(F) && cuddIsConstant(G)) return(dd->background);
+ return(NULL);
+
+} /* end of Cudd_addAgreement */
+
+
+/**Function********************************************************************
+
+ Synopsis [Disjunction of two 0-1 ADDs.]
+
+ Description [Disjunction of two 0-1 ADDs. Returns NULL
+ if not a terminal case; f OR g otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addOr(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+ DdNode *F, *G;
+
+ F = *f; G = *g;
+ if (F == DD_ONE(dd) || G == DD_ONE(dd)) return(DD_ONE(dd));
+ if (cuddIsConstant(F)) return(G);
+ if (cuddIsConstant(G)) return(F);
+ if (F == G) return(F);
+ if (F > G) { /* swap f and g */
+ *f = G;
+ *g = F;
+ }
+ return(NULL);
+
+} /* end of Cudd_addOr */
+
+
+/**Function********************************************************************
+
+ Synopsis [NAND of two 0-1 ADDs.]
+
+ Description [NAND of two 0-1 ADDs. Returns NULL
+ if not a terminal case; f NAND g otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addNand(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+ DdNode *F, *G;
+
+ F = *f; G = *g;
+ if (F == DD_ZERO(dd) || G == DD_ZERO(dd)) return(DD_ONE(dd));
+ if (cuddIsConstant(F) && cuddIsConstant(G)) return(DD_ZERO(dd));
+ if (F > G) { /* swap f and g */
+ *f = G;
+ *g = F;
+ }
+ return(NULL);
+
+} /* end of Cudd_addNand */
+
+
+/**Function********************************************************************
+
+ Synopsis [NOR of two 0-1 ADDs.]
+
+ Description [NOR of two 0-1 ADDs. Returns NULL
+ if not a terminal case; f NOR g otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addNor(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+ DdNode *F, *G;
+
+ F = *f; G = *g;
+ if (F == DD_ONE(dd) || G == DD_ONE(dd)) return(DD_ZERO(dd));
+ if (cuddIsConstant(F) && cuddIsConstant(G)) return(DD_ONE(dd));
+ if (F > G) { /* swap f and g */
+ *f = G;
+ *g = F;
+ }
+ return(NULL);
+
+} /* end of Cudd_addNor */
+
+
+/**Function********************************************************************
+
+ Synopsis [XOR of two 0-1 ADDs.]
+
+ Description [XOR of two 0-1 ADDs. Returns NULL
+ if not a terminal case; f XOR g otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addXor(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+ DdNode *F, *G;
+
+ F = *f; G = *g;
+ if (F == G) return(DD_ZERO(dd));
+ if (F == DD_ONE(dd) && G == DD_ZERO(dd)) return(DD_ONE(dd));
+ if (G == DD_ONE(dd) && F == DD_ZERO(dd)) return(DD_ONE(dd));
+ if (cuddIsConstant(F) && cuddIsConstant(G)) return(DD_ZERO(dd));
+ if (F > G) { /* swap f and g */
+ *f = G;
+ *g = F;
+ }
+ return(NULL);
+
+} /* end of Cudd_addXor */
+
+
+/**Function********************************************************************
+
+ Synopsis [XNOR of two 0-1 ADDs.]
+
+ Description [XNOR of two 0-1 ADDs. Returns NULL
+ if not a terminal case; f XNOR g otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addXnor(
+ DdManager * dd,
+ DdNode ** f,
+ DdNode ** g)
+{
+ DdNode *F, *G;
+
+ F = *f; G = *g;
+ if (F == G) return(DD_ONE(dd));
+ if (F == DD_ONE(dd) && G == DD_ONE(dd)) return(DD_ONE(dd));
+ if (G == DD_ZERO(dd) && F == DD_ZERO(dd)) return(DD_ONE(dd));
+ if (cuddIsConstant(F) && cuddIsConstant(G)) return(DD_ZERO(dd));
+ if (F > G) { /* swap f and g */
+ *f = G;
+ *g = F;
+ }
+ return(NULL);
+
+} /* end of Cudd_addXnor */
+
+
+/**Function********************************************************************
+
+ Synopsis [Applies op to the discriminants of f.]
+
+ Description [Applies op to the discriminants of f.
+ Returns a pointer to the result if succssful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addApply Cudd_addLog]
+
+******************************************************************************/
+DdNode *
+Cudd_addMonadicApply(
+ DdManager * dd,
+ DdNode * (*op)(DdManager *, DdNode *),
+ DdNode * f)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddAddMonadicApplyRecur(dd,op,f);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_addMonadicApply */
+
+
+/**Function********************************************************************
+
+ Synopsis [Natural logarithm of an ADD.]
+
+ Description [Natural logarithm of an ADDs. Returns NULL
+ if not a terminal case; log(f) otherwise. The discriminants of f must
+ be positive double's.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addMonadicApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addLog(
+ DdManager * dd,
+ DdNode * f)
+{
+ if (cuddIsConstant(f)) {
+ CUDD_VALUE_TYPE value = log(cuddV(f));
+ DdNode *res = cuddUniqueConst(dd,value);
+ return(res);
+ }
+ return(NULL);
+
+} /* end of Cudd_addLog */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addApply.]
+
+ Description [Performs the recursive step of Cudd_addApply. Returns a
+ pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddAddMonadicApplyRecur]
+
+******************************************************************************/
+DdNode *
+cuddAddApplyRecur(
+ DdManager * dd,
+ DdNode * (*op)(DdManager *, DdNode **, DdNode **),
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res,
+ *fv, *fvn, *gv, *gvn,
+ *T, *E;
+ unsigned int ford, gord;
+ unsigned int index;
+ DdNode *(*cacheOp)(DdManager *, DdNode *, DdNode *);
+
+ /* Check terminal cases. Op may swap f and g to increase the
+ * cache hit rate.
+ */
+ statLine(dd);
+ res = (*op)(dd,&f,&g);
+ if (res != NULL) return(res);
+
+ /* Check cache. */
+ cacheOp = (DdNode *(*)(DdManager *, DdNode *, DdNode *)) op;
+ res = cuddCacheLookup2(dd,cacheOp,f,g);
+ if (res != NULL) return(res);
+
+ /* Recursive step. */
+ ford = cuddI(dd,f->index);
+ gord = cuddI(dd,g->index);
+ if (ford <= gord) {
+ index = f->index;
+ fv = cuddT(f);
+ fvn = cuddE(f);
+ } else {
+ index = g->index;
+ fv = fvn = f;
+ }
+ if (gord <= ford) {
+ gv = cuddT(g);
+ gvn = cuddE(g);
+ } else {
+ gv = gvn = g;
+ }
+
+ T = cuddAddApplyRecur(dd,op,fv,gv);
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+
+ E = cuddAddApplyRecur(dd,op,fvn,gvn);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd,T);
+ return(NULL);
+ }
+ cuddRef(E);
+
+ res = (T == E) ? T : cuddUniqueInter(dd,(int)index,T,E);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ cuddDeref(T);
+ cuddDeref(E);
+
+ /* Store result. */
+ cuddCacheInsert2(dd,cacheOp,f,g,res);
+
+ return(res);
+
+} /* end of cuddAddApplyRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addMonadicApply.]
+
+ Description [Performs the recursive step of Cudd_addMonadicApply. Returns a
+ pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddAddApplyRecur]
+
+******************************************************************************/
+DdNode *
+cuddAddMonadicApplyRecur(
+ DdManager * dd,
+ DdNode * (*op)(DdManager *, DdNode *),
+ DdNode * f)
+{
+ DdNode *res, *ft, *fe, *T, *E;
+ unsigned int ford;
+ unsigned int index;
+
+ /* Check terminal cases. */
+ statLine(dd);
+ res = (*op)(dd,f);
+ if (res != NULL) return(res);
+
+ /* Check cache. */
+ res = cuddCacheLookup1(dd,op,f);
+ if (res != NULL) return(res);
+
+ /* Recursive step. */
+ ford = cuddI(dd,f->index);
+ index = f->index;
+ ft = cuddT(f);
+ fe = cuddE(f);
+
+ T = cuddAddMonadicApplyRecur(dd,op,ft);
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+
+ E = cuddAddMonadicApplyRecur(dd,op,fe);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd,T);
+ return(NULL);
+ }
+ cuddRef(E);
+
+ res = (T == E) ? T : cuddUniqueInter(dd,(int)index,T,E);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ cuddDeref(T);
+ cuddDeref(E);
+
+ /* Store result. */
+ cuddCacheInsert1(dd,op,f,res);
+
+ return(res);
+
+} /* end of cuddAddMonadicApplyRecur */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
diff --git a/src/bdd/cudd/cuddAddFind.c b/src/bdd/cudd/cuddAddFind.c
new file mode 100644
index 00000000..3399527a
--- /dev/null
+++ b/src/bdd/cudd/cuddAddFind.c
@@ -0,0 +1,283 @@
+/**CFile***********************************************************************
+
+ FileName [cuddAddFind.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions to find maximum and minimum in an ADD and to
+ extract the i-th bit.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_addFindMax()
+ <li> Cudd_addFindMin()
+ <li> Cudd_addIthBit()
+ </ul>
+ Static functions included in this module:
+ <ul>
+ <li> addDoIthBit()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddAddFind.c,v 1.1.1.1 2003/02/24 22:23:50 wjiang Exp $";
+#endif
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static DdNode * addDoIthBit ARGS((DdManager *dd, DdNode *f, DdNode *index));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Finds the maximum discriminant of f.]
+
+ Description [Returns a pointer to a constant ADD.]
+
+ SideEffects [None]
+
+******************************************************************************/
+DdNode *
+Cudd_addFindMax(
+ DdManager * dd,
+ DdNode * f)
+{
+ DdNode *t, *e, *res;
+
+ statLine(dd);
+ if (cuddIsConstant(f)) {
+ return(f);
+ }
+
+ res = cuddCacheLookup1(dd,Cudd_addFindMax,f);
+ if (res != NULL) {
+ return(res);
+ }
+
+ t = Cudd_addFindMax(dd,cuddT(f));
+ if (t == DD_PLUS_INFINITY(dd)) return(t);
+
+ e = Cudd_addFindMax(dd,cuddE(f));
+
+ res = (cuddV(t) >= cuddV(e)) ? t : e;
+
+ cuddCacheInsert1(dd,Cudd_addFindMax,f,res);
+
+ return(res);
+
+} /* end of Cudd_addFindMax */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the minimum discriminant of f.]
+
+ Description [Returns a pointer to a constant ADD.]
+
+ SideEffects [None]
+
+******************************************************************************/
+DdNode *
+Cudd_addFindMin(
+ DdManager * dd,
+ DdNode * f)
+{
+ DdNode *t, *e, *res;
+
+ statLine(dd);
+ if (cuddIsConstant(f)) {
+ return(f);
+ }
+
+ res = cuddCacheLookup1(dd,Cudd_addFindMin,f);
+ if (res != NULL) {
+ return(res);
+ }
+
+ t = Cudd_addFindMin(dd,cuddT(f));
+ if (t == DD_MINUS_INFINITY(dd)) return(t);
+
+ e = Cudd_addFindMin(dd,cuddE(f));
+
+ res = (cuddV(t) <= cuddV(e)) ? t : e;
+
+ cuddCacheInsert1(dd,Cudd_addFindMin,f,res);
+
+ return(res);
+
+} /* end of Cudd_addFindMin */
+
+
+/**Function********************************************************************
+
+ Synopsis [Extracts the i-th bit from an ADD.]
+
+ Description [Produces an ADD from another ADD by replacing all
+ discriminants whose i-th bit is equal to 1 with 1, and all other
+ discriminants with 0. The i-th bit refers to the integer
+ representation of the leaf value. If the value is has a fractional
+ part, it is ignored. Repeated calls to this procedure allow one to
+ transform an integer-valued ADD into an array of ADDs, one for each
+ bit of the leaf values. Returns a pointer to the resulting ADD if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addBddIthBit]
+
+******************************************************************************/
+DdNode *
+Cudd_addIthBit(
+ DdManager * dd,
+ DdNode * f,
+ int bit)
+{
+ DdNode *res;
+ DdNode *index;
+
+ /* Use a constant node to remember the bit, so that we can use the
+ ** global cache.
+ */
+ index = cuddUniqueConst(dd,(CUDD_VALUE_TYPE) bit);
+ if (index == NULL) return(NULL);
+ cuddRef(index);
+
+ do {
+ dd->reordered = 0;
+ res = addDoIthBit(dd, f, index);
+ } while (dd->reordered == 1);
+
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, index);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd, index);
+ cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_addIthBit */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step for Cudd_addIthBit.]
+
+ Description [Performs the recursive step for Cudd_addIthBit.
+ Returns a pointer to the BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+addDoIthBit(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * index)
+{
+ DdNode *res, *T, *E;
+ DdNode *fv, *fvn;
+ int mask, value;
+ int v;
+
+ statLine(dd);
+ /* Check terminal case. */
+ if (cuddIsConstant(f)) {
+ mask = 1 << ((int) cuddV(index));
+ value = (int) cuddV(f);
+ return((value & mask) == 0 ? DD_ZERO(dd) : DD_ONE(dd));
+ }
+
+ /* Check cache. */
+ res = cuddCacheLookup2(dd,addDoIthBit,f,index);
+ if (res != NULL) return(res);
+
+ /* Recursive step. */
+ v = f->index;
+ fv = cuddT(f); fvn = cuddE(f);
+
+ T = addDoIthBit(dd,fv,index);
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+
+ E = addDoIthBit(dd,fvn,index);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ return(NULL);
+ }
+ cuddRef(E);
+
+ res = (T == E) ? T : cuddUniqueInter(dd,v,T,E);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ cuddDeref(T);
+ cuddDeref(E);
+
+ /* Store result. */
+ cuddCacheInsert2(dd,addDoIthBit,f,index,res);
+
+ return(res);
+
+} /* end of addDoIthBit */
+
diff --git a/src/bdd/cudd/cuddAddInv.c b/src/bdd/cudd/cuddAddInv.c
new file mode 100644
index 00000000..cb6dbfbe
--- /dev/null
+++ b/src/bdd/cudd/cuddAddInv.c
@@ -0,0 +1,172 @@
+/**CFile***********************************************************************
+
+ FileName [cuddAddInv.c]
+
+ PackageName [cudd]
+
+ Synopsis [Function to compute the scalar inverse of an ADD.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_addScalarInverse()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddAddScalarInverseRecur()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddAddInv.c,v 1.1.1.1 2003/02/24 22:23:50 wjiang Exp $";
+#endif
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the scalar inverse of an ADD.]
+
+ Description [Computes an n ADD where the discriminants are the
+ multiplicative inverses of the corresponding discriminants of the
+ argument ADD. Returns a pointer to the resulting ADD in case of
+ success. Returns NULL if any discriminants smaller than epsilon is
+ encountered.]
+
+ SideEffects [None]
+
+******************************************************************************/
+DdNode *
+Cudd_addScalarInverse(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * epsilon)
+{
+ DdNode *res;
+
+ if (!cuddIsConstant(epsilon)) {
+ (void) fprintf(dd->err,"Invalid epsilon\n");
+ return(NULL);
+ }
+ do {
+ dd->reordered = 0;
+ res = cuddAddScalarInverseRecur(dd,f,epsilon);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_addScalarInverse */
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of addScalarInverse.]
+
+ Description [Returns a pointer to the resulting ADD in case of
+ success. Returns NULL if any discriminants smaller than epsilon is
+ encountered.]
+
+ SideEffects [None]
+
+******************************************************************************/
+DdNode *
+cuddAddScalarInverseRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * epsilon)
+{
+ DdNode *t, *e, *res;
+ CUDD_VALUE_TYPE value;
+
+ statLine(dd);
+ if (cuddIsConstant(f)) {
+ if (ddAbs(cuddV(f)) < cuddV(epsilon)) return(NULL);
+ value = 1.0 / cuddV(f);
+ res = cuddUniqueConst(dd,value);
+ return(res);
+ }
+
+ res = cuddCacheLookup2(dd,Cudd_addScalarInverse,f,epsilon);
+ if (res != NULL) return(res);
+
+ t = cuddAddScalarInverseRecur(dd,cuddT(f),epsilon);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+
+ e = cuddAddScalarInverseRecur(dd,cuddE(f),epsilon);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ res = (t == e) ? t : cuddUniqueInter(dd,(int)f->index,t,e);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ Cudd_RecursiveDeref(dd, e);
+ return(NULL);
+ }
+
+ cuddCacheInsert2(dd,Cudd_addScalarInverse,f,epsilon,res);
+
+ return(res);
+
+} /* end of cuddAddScalarInverseRecur */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
diff --git a/src/bdd/cudd/cuddAddIte.c b/src/bdd/cudd/cuddAddIte.c
new file mode 100644
index 00000000..77c4d18a
--- /dev/null
+++ b/src/bdd/cudd/cuddAddIte.c
@@ -0,0 +1,613 @@
+/**CFile***********************************************************************
+
+ FileName [cuddAddIte.c]
+
+ PackageName [cudd]
+
+ Synopsis [ADD ITE function and satellites.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_addIte()
+ <li> Cudd_addIteConstant()
+ <li> Cudd_addEvalConst()
+ <li> Cudd_addCmpl()
+ <li> Cudd_addLeq()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddAddIteRecur()
+ <li> cuddAddCmplRecur()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> addVarToConst()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddAddIte.c,v 1.1.1.1 2003/02/24 22:23:50 wjiang Exp $";
+#endif
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static void addVarToConst ARGS((DdNode *f, DdNode **gp, DdNode **hp, DdNode *one, DdNode *zero));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements ITE(f,g,h).]
+
+ Description [Implements ITE(f,g,h). This procedure assumes that f is
+ a 0-1 ADD. Returns a pointer to the resulting ADD if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddIte Cudd_addIteConstant Cudd_addApply]
+
+******************************************************************************/
+DdNode *
+Cudd_addIte(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ DdNode * h)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddAddIteRecur(dd,f,g,h);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_addIte */
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements ITEconstant for ADDs.]
+
+ Description [Implements ITEconstant for ADDs. f must be a 0-1 ADD.
+ Returns a pointer to the resulting ADD (which may or may not be
+ constant) or DD_NON_CONSTANT. No new nodes are created. This function
+ can be used, for instance, to check that g has a constant value
+ (specified by h) whenever f is 1. If the constant value is unknown,
+ then one should use Cudd_addEvalConst.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addIte Cudd_addEvalConst Cudd_bddIteConstant]
+
+******************************************************************************/
+DdNode *
+Cudd_addIteConstant(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ DdNode * h)
+{
+ DdNode *one,*zero;
+ DdNode *Fv,*Fnv,*Gv,*Gnv,*Hv,*Hnv,*r,*t,*e;
+ unsigned int topf,topg,toph,v;
+
+ statLine(dd);
+ /* Trivial cases. */
+ if (f == (one = DD_ONE(dd))) { /* ITE(1,G,H) = G */
+ return(g);
+ }
+ if (f == (zero = DD_ZERO(dd))) { /* ITE(0,G,H) = H */
+ return(h);
+ }
+
+ /* From now on, f is known not to be a constant. */
+ addVarToConst(f,&g,&h,one,zero);
+
+ /* Check remaining one variable cases. */
+ if (g == h) { /* ITE(F,G,G) = G */
+ return(g);
+ }
+ if (cuddIsConstant(g) && cuddIsConstant(h)) {
+ return(DD_NON_CONSTANT);
+ }
+
+ topf = cuddI(dd,f->index);
+ topg = cuddI(dd,g->index);
+ toph = cuddI(dd,h->index);
+ v = ddMin(topg,toph);
+
+ /* ITE(F,G,H) = (x,G,H) (non constant) if F = (x,1,0), x < top(G,H). */
+ if (topf < v && cuddIsConstant(cuddT(f)) && cuddIsConstant(cuddE(f))) {
+ return(DD_NON_CONSTANT);
+ }
+
+ /* Check cache. */
+ r = cuddConstantLookup(dd,DD_ADD_ITE_CONSTANT_TAG,f,g,h);
+ if (r != NULL) {
+ return(r);
+ }
+
+ /* Compute cofactors. */
+ if (topf <= v) {
+ v = ddMin(topf,v); /* v = top_var(F,G,H) */
+ Fv = cuddT(f); Fnv = cuddE(f);
+ } else {
+ Fv = Fnv = f;
+ }
+ if (topg == v) {
+ Gv = cuddT(g); Gnv = cuddE(g);
+ } else {
+ Gv = Gnv = g;
+ }
+ if (toph == v) {
+ Hv = cuddT(h); Hnv = cuddE(h);
+ } else {
+ Hv = Hnv = h;
+ }
+
+ /* Recursive step. */
+ t = Cudd_addIteConstant(dd,Fv,Gv,Hv);
+ if (t == DD_NON_CONSTANT || !cuddIsConstant(t)) {
+ cuddCacheInsert(dd, DD_ADD_ITE_CONSTANT_TAG, f, g, h, DD_NON_CONSTANT);
+ return(DD_NON_CONSTANT);
+ }
+ e = Cudd_addIteConstant(dd,Fnv,Gnv,Hnv);
+ if (e == DD_NON_CONSTANT || !cuddIsConstant(e) || t != e) {
+ cuddCacheInsert(dd, DD_ADD_ITE_CONSTANT_TAG, f, g, h, DD_NON_CONSTANT);
+ return(DD_NON_CONSTANT);
+ }
+ cuddCacheInsert(dd, DD_ADD_ITE_CONSTANT_TAG, f, g, h, t);
+ return(t);
+
+} /* end of Cudd_addIteConstant */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether ADD g is constant whenever ADD f is 1.]
+
+ Description [Checks whether ADD g is constant whenever ADD f is 1. f
+ must be a 0-1 ADD. Returns a pointer to the resulting ADD (which may
+ or may not be constant) or DD_NON_CONSTANT. If f is identically 0,
+ the check is assumed to be successful, and the background value is
+ returned. No new nodes are created.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addIteConstant Cudd_addLeq]
+
+******************************************************************************/
+DdNode *
+Cudd_addEvalConst(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *zero;
+ DdNode *Fv,*Fnv,*Gv,*Gnv,*r,*t,*e;
+ unsigned int topf,topg;
+
+#ifdef DD_DEBUG
+ assert(!Cudd_IsComplement(f));
+#endif
+
+ statLine(dd);
+ /* Terminal cases. */
+ if (f == DD_ONE(dd) || cuddIsConstant(g)) {
+ return(g);
+ }
+ if (f == (zero = DD_ZERO(dd))) {
+ return(dd->background);
+ }
+
+#ifdef DD_DEBUG
+ assert(!cuddIsConstant(f));
+#endif
+ /* From now on, f and g are known not to be constants. */
+
+ topf = cuddI(dd,f->index);
+ topg = cuddI(dd,g->index);
+
+ /* Check cache. */
+ r = cuddConstantLookup(dd,DD_ADD_EVAL_CONST_TAG,f,g,g);
+ if (r != NULL) {
+ return(r);
+ }
+
+ /* Compute cofactors. */
+ if (topf <= topg) {
+ Fv = cuddT(f); Fnv = cuddE(f);
+ } else {
+ Fv = Fnv = f;
+ }
+ if (topg <= topf) {
+ Gv = cuddT(g); Gnv = cuddE(g);
+ } else {
+ Gv = Gnv = g;
+ }
+
+ /* Recursive step. */
+ if (Fv != zero) {
+ t = Cudd_addEvalConst(dd,Fv,Gv);
+ if (t == DD_NON_CONSTANT || !cuddIsConstant(t)) {
+ cuddCacheInsert2(dd, Cudd_addEvalConst, f, g, DD_NON_CONSTANT);
+ return(DD_NON_CONSTANT);
+ }
+ if (Fnv != zero) {
+ e = Cudd_addEvalConst(dd,Fnv,Gnv);
+ if (e == DD_NON_CONSTANT || !cuddIsConstant(e) || t != e) {
+ cuddCacheInsert2(dd, Cudd_addEvalConst, f, g, DD_NON_CONSTANT);
+ return(DD_NON_CONSTANT);
+ }
+ }
+ cuddCacheInsert2(dd,Cudd_addEvalConst,f,g,t);
+ return(t);
+ } else { /* Fnv must be != zero */
+ e = Cudd_addEvalConst(dd,Fnv,Gnv);
+ cuddCacheInsert2(dd, Cudd_addEvalConst, f, g, e);
+ return(e);
+ }
+
+} /* end of Cudd_addEvalConst */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the complement of an ADD a la C language.]
+
+ Description [Computes the complement of an ADD a la C language: The
+ complement of 0 is 1 and the complement of everything else is 0.
+ Returns a pointer to the resulting ADD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addNegate]
+
+******************************************************************************/
+DdNode *
+Cudd_addCmpl(
+ DdManager * dd,
+ DdNode * f)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddAddCmplRecur(dd,f);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_addCmpl */
+
+
+/**Function********************************************************************
+
+ Synopsis [Determines whether f is less than or equal to g.]
+
+ Description [Returns 1 if f is less than or equal to g; 0 otherwise.
+ No new nodes are created. This procedure works for arbitrary ADDs.
+ For 0-1 ADDs Cudd_addEvalConst is more efficient.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addIteConstant Cudd_addEvalConst Cudd_bddLeq]
+
+******************************************************************************/
+int
+Cudd_addLeq(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *tmp, *fv, *fvn, *gv, *gvn;
+ unsigned int topf, topg, res;
+
+ /* Terminal cases. */
+ if (f == g) return(1);
+
+ statLine(dd);
+ if (cuddIsConstant(f)) {
+ if (cuddIsConstant(g)) return(cuddV(f) <= cuddV(g));
+ if (f == DD_MINUS_INFINITY(dd)) return(1);
+ if (f == DD_PLUS_INFINITY(dd)) return(0); /* since f != g */
+ }
+ if (g == DD_PLUS_INFINITY(dd)) return(1);
+ if (g == DD_MINUS_INFINITY(dd)) return(0); /* since f != g */
+
+ /* Check cache. */
+ tmp = cuddCacheLookup2(dd,(DdNode * (*)(DdManager *, DdNode *,
+ DdNode *))Cudd_addLeq,f,g);
+ if (tmp != NULL) {
+ return(tmp == DD_ONE(dd));
+ }
+
+ /* Compute cofactors. One of f and g is not constant. */
+ topf = cuddI(dd,f->index);
+ topg = cuddI(dd,g->index);
+ if (topf <= topg) {
+ fv = cuddT(f); fvn = cuddE(f);
+ } else {
+ fv = fvn = f;
+ }
+ if (topg <= topf) {
+ gv = cuddT(g); gvn = cuddE(g);
+ } else {
+ gv = gvn = g;
+ }
+
+ res = Cudd_addLeq(dd,fvn,gvn) && Cudd_addLeq(dd,fv,gv);
+
+ /* Store result in cache and return. */
+ cuddCacheInsert2(dd,(DdNode * (*)(DdManager *, DdNode *, DdNode *))
+ Cudd_addLeq,f,g,Cudd_NotCond(DD_ONE(dd),res==0));
+ return(res);
+
+} /* end of Cudd_addLeq */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_addIte(f,g,h).]
+
+ Description [Implements the recursive step of Cudd_addIte(f,g,h).
+ Returns a pointer to the resulting ADD if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addIte]
+
+******************************************************************************/
+DdNode *
+cuddAddIteRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ DdNode * h)
+{
+ DdNode *one,*zero;
+ DdNode *r,*Fv,*Fnv,*Gv,*Gnv,*Hv,*Hnv,*t,*e;
+ unsigned int topf,topg,toph,v;
+ int index;
+
+ statLine(dd);
+ /* Trivial cases. */
+
+ /* One variable cases. */
+ if (f == (one = DD_ONE(dd))) { /* ITE(1,G,H) = G */
+ return(g);
+ }
+ if (f == (zero = DD_ZERO(dd))) { /* ITE(0,G,H) = H */
+ return(h);
+ }
+
+ /* From now on, f is known to not be a constant. */
+ addVarToConst(f,&g,&h,one,zero);
+
+ /* Check remaining one variable cases. */
+ if (g == h) { /* ITE(F,G,G) = G */
+ return(g);
+ }
+
+ if (g == one) { /* ITE(F,1,0) = F */
+ if (h == zero) return(f);
+ }
+
+ topf = cuddI(dd,f->index);
+ topg = cuddI(dd,g->index);
+ toph = cuddI(dd,h->index);
+ v = ddMin(topg,toph);
+
+ /* A shortcut: ITE(F,G,H) = (x,G,H) if F=(x,1,0), x < top(G,H). */
+ if (topf < v && cuddT(f) == one && cuddE(f) == zero) {
+ r = cuddUniqueInter(dd,(int)f->index,g,h);
+ return(r);
+ }
+ if (topf < v && cuddT(f) == zero && cuddE(f) == one) {
+ r = cuddUniqueInter(dd,(int)f->index,h,g);
+ return(r);
+ }
+
+ /* Check cache. */
+ r = cuddCacheLookup(dd,DD_ADD_ITE_TAG,f,g,h);
+ if (r != NULL) {
+ return(r);
+ }
+
+ /* Compute cofactors. */
+ if (topf <= v) {
+ v = ddMin(topf,v); /* v = top_var(F,G,H) */
+ index = f->index;
+ Fv = cuddT(f); Fnv = cuddE(f);
+ } else {
+ Fv = Fnv = f;
+ }
+ if (topg == v) {
+ index = g->index;
+ Gv = cuddT(g); Gnv = cuddE(g);
+ } else {
+ Gv = Gnv = g;
+ }
+ if (toph == v) {
+ index = h->index;
+ Hv = cuddT(h); Hnv = cuddE(h);
+ } else {
+ Hv = Hnv = h;
+ }
+
+ /* Recursive step. */
+ t = cuddAddIteRecur(dd,Fv,Gv,Hv);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+
+ e = cuddAddIteRecur(dd,Fnv,Gnv,Hnv);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(dd,t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ r = (t == e) ? t : cuddUniqueInter(dd,index,t,e);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd,t);
+ Cudd_RecursiveDeref(dd,e);
+ return(NULL);
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+
+ cuddCacheInsert(dd,DD_ADD_ITE_TAG,f,g,h,r);
+
+ return(r);
+
+} /* end of cuddAddIteRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addCmpl.]
+
+ Description [Performs the recursive step of Cudd_addCmpl. Returns a
+ pointer to the resulting ADD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addCmpl]
+
+******************************************************************************/
+DdNode *
+cuddAddCmplRecur(
+ DdManager * dd,
+ DdNode * f)
+{
+ DdNode *one,*zero;
+ DdNode *r,*Fv,*Fnv,*t,*e;
+
+ statLine(dd);
+ one = DD_ONE(dd);
+ zero = DD_ZERO(dd);
+
+ if (cuddIsConstant(f)) {
+ if (f == zero) {
+ return(one);
+ } else {
+ return(zero);
+ }
+ }
+ r = cuddCacheLookup1(dd,Cudd_addCmpl,f);
+ if (r != NULL) {
+ return(r);
+ }
+ Fv = cuddT(f);
+ Fnv = cuddE(f);
+ t = cuddAddCmplRecur(dd,Fv);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ e = cuddAddCmplRecur(dd,Fnv);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(dd,t);
+ return(NULL);
+ }
+ cuddRef(e);
+ r = (t == e) ? t : cuddUniqueInter(dd,(int)f->index,t,e);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ Cudd_RecursiveDeref(dd, e);
+ return(NULL);
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+ cuddCacheInsert1(dd,Cudd_addCmpl,f,r);
+ return(r);
+
+} /* end of cuddAddCmplRecur */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Replaces variables with constants if possible (part of
+ canonical form).]
+
+ Description []
+
+ SideEffects [None]
+
+******************************************************************************/
+static void
+addVarToConst(
+ DdNode * f,
+ DdNode ** gp,
+ DdNode ** hp,
+ DdNode * one,
+ DdNode * zero)
+{
+ DdNode *g = *gp;
+ DdNode *h = *hp;
+
+ if (f == g) { /* ITE(F,F,H) = ITE(F,1,H) = F + H */
+ *gp = one;
+ }
+
+ if (f == h) { /* ITE(F,G,F) = ITE(F,G,0) = F * G */
+ *hp = zero;
+ }
+
+} /* end of addVarToConst */
diff --git a/src/bdd/cudd/cuddAddNeg.c b/src/bdd/cudd/cuddAddNeg.c
new file mode 100644
index 00000000..2420df64
--- /dev/null
+++ b/src/bdd/cudd/cuddAddNeg.c
@@ -0,0 +1,262 @@
+/**CFile***********************************************************************
+
+ FileName [cuddAddNeg.c]
+
+ PackageName [cudd]
+
+ Synopsis [function to compute the negation of an ADD.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_addNegate()
+ <li> Cudd_addRoundOff()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddAddNegateRecur()
+ <li> cuddAddRoundOffRecur()
+ </ul> ]
+
+ Author [Fabio Somenzi, Balakrishna Kumthekar]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddAddNeg.c,v 1.1.1.1 2003/02/24 22:23:50 wjiang Exp $";
+#endif
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Computes the additive inverse of an ADD.]
+
+ Description [Computes the additive inverse of an ADD. Returns a pointer
+ to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addCmpl]
+
+******************************************************************************/
+DdNode *
+Cudd_addNegate(
+ DdManager * dd,
+ DdNode * f)
+{
+ DdNode *res;
+
+ do {
+ res = cuddAddNegateRecur(dd,f);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_addNegate */
+
+
+/**Function********************************************************************
+
+ Synopsis [Rounds off the discriminants of an ADD.]
+
+ Description [Rounds off the discriminants of an ADD. The discriminants are
+ rounded off to N digits after the decimal. Returns a pointer to the result
+ ADD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_addRoundOff(
+ DdManager * dd,
+ DdNode * f,
+ int N)
+{
+ DdNode *res;
+ double trunc = pow(10.0,(double)N);
+
+ do {
+ res = cuddAddRoundOffRecur(dd,f,trunc);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_addRoundOff */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_addNegate.]
+
+ Description [Implements the recursive step of Cudd_addNegate.
+ Returns a pointer to the result.]
+
+ SideEffects [None]
+
+******************************************************************************/
+DdNode *
+cuddAddNegateRecur(
+ DdManager * dd,
+ DdNode * f)
+{
+ DdNode *res,
+ *fv, *fvn,
+ *T, *E;
+
+ statLine(dd);
+ /* Check terminal cases. */
+ if (cuddIsConstant(f)) {
+ res = cuddUniqueConst(dd,-cuddV(f));
+ return(res);
+ }
+
+ /* Check cache */
+ res = cuddCacheLookup1(dd,Cudd_addNegate,f);
+ if (res != NULL) return(res);
+
+ /* Recursive Step */
+ fv = cuddT(f);
+ fvn = cuddE(f);
+ T = cuddAddNegateRecur(dd,fv);
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+
+ E = cuddAddNegateRecur(dd,fvn);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd,T);
+ return(NULL);
+ }
+ cuddRef(E);
+ res = (T == E) ? T : cuddUniqueInter(dd,(int)f->index,T,E);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ cuddDeref(T);
+ cuddDeref(E);
+
+ /* Store result. */
+ cuddCacheInsert1(dd,Cudd_addNegate,f,res);
+
+ return(res);
+
+} /* end of cuddAddNegateRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_addRoundOff.]
+
+ Description [Implements the recursive step of Cudd_addRoundOff.
+ Returns a pointer to the result.]
+
+ SideEffects [None]
+
+******************************************************************************/
+DdNode *
+cuddAddRoundOffRecur(
+ DdManager * dd,
+ DdNode * f,
+ double trunc)
+{
+
+ DdNode *res, *fv, *fvn, *T, *E;
+ double n;
+ DdNode *(*cacheOp)(DdManager *, DdNode *);
+
+ statLine(dd);
+ if (cuddIsConstant(f)) {
+ n = ceil(cuddV(f)*trunc)/trunc;
+ res = cuddUniqueConst(dd,n);
+ return(res);
+ }
+ cacheOp = (DdNode *(*)(DdManager *, DdNode *)) Cudd_addRoundOff;
+ res = cuddCacheLookup1(dd,cacheOp,f);
+ if (res != NULL) {
+ return(res);
+ }
+ /* Recursive Step */
+ fv = cuddT(f);
+ fvn = cuddE(f);
+ T = cuddAddRoundOffRecur(dd,fv,trunc);
+ if (T == NULL) {
+ return(NULL);
+ }
+ cuddRef(T);
+ E = cuddAddRoundOffRecur(dd,fvn,trunc);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd,T);
+ return(NULL);
+ }
+ cuddRef(E);
+ res = (T == E) ? T : cuddUniqueInter(dd,(int)f->index,T,E);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd,T);
+ Cudd_RecursiveDeref(dd,E);
+ return(NULL);
+ }
+ cuddDeref(T);
+ cuddDeref(E);
+
+ /* Store result. */
+ cuddCacheInsert1(dd,cacheOp,f,res);
+ return(res);
+
+} /* end of cuddAddRoundOffRecur */
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
diff --git a/src/bdd/cudd/cuddAddWalsh.c b/src/bdd/cudd/cuddAddWalsh.c
new file mode 100644
index 00000000..980ee215
--- /dev/null
+++ b/src/bdd/cudd/cuddAddWalsh.c
@@ -0,0 +1,364 @@
+/**CFile***********************************************************************
+
+ FileName [cuddAddWalsh.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions that generate Walsh matrices and residue
+ functions in ADD form.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_addWalsh()
+ <li> Cudd_addResidue()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> addWalshInt()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddAddWalsh.c,v 1.1.1.1 2003/02/24 22:23:50 wjiang Exp $";
+#endif
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static DdNode * addWalshInt ARGS((DdManager *dd, DdNode **x, DdNode **y, int n));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Generates a Walsh matrix in ADD form.]
+
+ Description [Generates a Walsh matrix in ADD form. Returns a pointer
+ to the matrixi if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+DdNode *
+Cudd_addWalsh(
+ DdManager * dd,
+ DdNode ** x,
+ DdNode ** y,
+ int n)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = addWalshInt(dd, x, y, n);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_addWalsh */
+
+
+/**Function********************************************************************
+
+ Synopsis [Builds an ADD for the residue modulo m of an n-bit
+ number.]
+
+ Description [Builds an ADD for the residue modulo m of an n-bit
+ number. The modulus must be at least 2, and the number of bits at
+ least 1. Parameter options specifies whether the MSB should be on top
+ or the LSB; and whther the number whose residue is computed is in
+ two's complement notation or not. The macro CUDD_RESIDUE_DEFAULT
+ specifies LSB on top and unsigned number. The macro CUDD_RESIDUE_MSB
+ specifies MSB on top, and the macro CUDD_RESIDUE_TC specifies two's
+ complement residue. To request MSB on top and two's complement residue
+ simultaneously, one can OR the two macros:
+ CUDD_RESIDUE_MSB | CUDD_RESIDUE_TC.
+ Cudd_addResidue returns a pointer to the resulting ADD if successful;
+ NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_addResidue(
+ DdManager * dd /* manager */,
+ int n /* number of bits */,
+ int m /* modulus */,
+ int options /* options */,
+ int top /* index of top variable */)
+{
+ int msbLsb; /* MSB on top (1) or LSB on top (0) */
+ int tc; /* two's complement (1) or unsigned (0) */
+ int i, j, k, t, residue, thisOne, previous, index;
+ DdNode **array[2], *var, *tmp, *res;
+
+ /* Sanity check. */
+ if (n < 1 && m < 2) return(NULL);
+
+ msbLsb = options & CUDD_RESIDUE_MSB;
+ tc = options & CUDD_RESIDUE_TC;
+
+ /* Allocate and initialize working arrays. */
+ array[0] = ALLOC(DdNode *,m);
+ if (array[0] == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ array[1] = ALLOC(DdNode *,m);
+ if (array[1] == NULL) {
+ FREE(array[0]);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < m; i++) {
+ array[0][i] = array[1][i] = NULL;
+ }
+
+ /* Initialize residues. */
+ for (i = 0; i < m; i++) {
+ tmp = cuddUniqueConst(dd,(CUDD_VALUE_TYPE) i);
+ if (tmp == NULL) {
+ for (j = 0; j < i; j++) {
+ Cudd_RecursiveDeref(dd,array[1][j]);
+ }
+ FREE(array[0]);
+ FREE(array[1]);
+ return(NULL);
+ }
+ cuddRef(tmp);
+ array[1][i] = tmp;
+ }
+
+ /* Main iteration. */
+ residue = 1; /* residue of 2**0 */
+ for (k = 0; k < n; k++) {
+ /* Choose current and previous arrays. */
+ thisOne = k & 1;
+ previous = thisOne ^ 1;
+ /* Build an ADD projection function. */
+ if (msbLsb) {
+ index = top+n-k-1;
+ } else {
+ index = top+k;
+ }
+ var = cuddUniqueInter(dd,index,DD_ONE(dd),DD_ZERO(dd));
+ if (var == NULL) {
+ for (j = 0; j < m; j++) {
+ Cudd_RecursiveDeref(dd,array[previous][j]);
+ }
+ FREE(array[0]);
+ FREE(array[1]);
+ return(NULL);
+ }
+ cuddRef(var);
+ for (i = 0; i < m; i ++) {
+ t = (i + residue) % m;
+ tmp = Cudd_addIte(dd,var,array[previous][t],array[previous][i]);
+ if (tmp == NULL) {
+ for (j = 0; j < i; j++) {
+ Cudd_RecursiveDeref(dd,array[thisOne][j]);
+ }
+ for (j = 0; j < m; j++) {
+ Cudd_RecursiveDeref(dd,array[previous][j]);
+ }
+ FREE(array[0]);
+ FREE(array[1]);
+ return(NULL);
+ }
+ cuddRef(tmp);
+ array[thisOne][i] = tmp;
+ }
+ /* One layer completed. Free the other array for the next iteration. */
+ for (i = 0; i < m; i++) {
+ Cudd_RecursiveDeref(dd,array[previous][i]);
+ }
+ Cudd_RecursiveDeref(dd,var);
+ /* Update residue of 2**k. */
+ residue = (2 * residue) % m;
+ /* Adjust residue for MSB, if this is a two's complement number. */
+ if (tc && (k == n - 1)) {
+ residue = (m - residue) % m;
+ }
+ }
+
+ /* We are only interested in the 0-residue node of the top layer. */
+ for (i = 1; i < m; i++) {
+ Cudd_RecursiveDeref(dd,array[(n - 1) & 1][i]);
+ }
+ res = array[(n - 1) & 1][0];
+
+ FREE(array[0]);
+ FREE(array[1]);
+
+ cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_addResidue */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_addWalsh.]
+
+ Description [Generates a Walsh matrix in ADD form. Returns a pointer
+ to the matrixi if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static DdNode *
+addWalshInt(
+ DdManager * dd,
+ DdNode ** x,
+ DdNode ** y,
+ int n)
+{
+ DdNode *one, *minusone;
+ DdNode *t, *u, *t1, *u1, *v, *w;
+ int i;
+
+ one = DD_ONE(dd);
+ if (n == 0) return(one);
+
+ /* Build bottom part of ADD outside loop */
+ minusone = cuddUniqueConst(dd,(CUDD_VALUE_TYPE) -1);
+ if (minusone == NULL) return(NULL);
+ cuddRef(minusone);
+ v = Cudd_addIte(dd, y[n-1], minusone, one);
+ if (v == NULL) {
+ Cudd_RecursiveDeref(dd, minusone);
+ return(NULL);
+ }
+ cuddRef(v);
+ u = Cudd_addIte(dd, x[n-1], v, one);
+ if (u == NULL) {
+ Cudd_RecursiveDeref(dd, minusone);
+ Cudd_RecursiveDeref(dd, v);
+ return(NULL);
+ }
+ cuddRef(u);
+ Cudd_RecursiveDeref(dd, v);
+ if (n>1) {
+ w = Cudd_addIte(dd, y[n-1], one, minusone);
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, minusone);
+ Cudd_RecursiveDeref(dd, u);
+ return(NULL);
+ }
+ cuddRef(w);
+ t = Cudd_addIte(dd, x[n-1], w, minusone);
+ if (t == NULL) {
+ Cudd_RecursiveDeref(dd, minusone);
+ Cudd_RecursiveDeref(dd, u);
+ Cudd_RecursiveDeref(dd, w);
+ return(NULL);
+ }
+ cuddRef(t);
+ Cudd_RecursiveDeref(dd, w);
+ }
+ cuddDeref(minusone); /* minusone is in the result; it won't die */
+
+ /* Loop to build the rest of the ADD */
+ for (i=n-2; i>=0; i--) {
+ t1 = t; u1 = u;
+ v = Cudd_addIte(dd, y[i], t1, u1);
+ if (v == NULL) {
+ Cudd_RecursiveDeref(dd, u1);
+ Cudd_RecursiveDeref(dd, t1);
+ return(NULL);
+ }
+ cuddRef(v);
+ u = Cudd_addIte(dd, x[i], v, u1);
+ if (u == NULL) {
+ Cudd_RecursiveDeref(dd, u1);
+ Cudd_RecursiveDeref(dd, t1);
+ Cudd_RecursiveDeref(dd, v);
+ return(NULL);
+ }
+ cuddRef(u);
+ Cudd_RecursiveDeref(dd, v);
+ if (i>0) {
+ w = Cudd_addIte(dd, y[i], u1, t1);
+ if (u == NULL) {
+ Cudd_RecursiveDeref(dd, u1);
+ Cudd_RecursiveDeref(dd, t1);
+ Cudd_RecursiveDeref(dd, u);
+ return(NULL);
+ }
+ cuddRef(w);
+ t = Cudd_addIte(dd, x[i], w, t1);
+ if (u == NULL) {
+ Cudd_RecursiveDeref(dd, u1);
+ Cudd_RecursiveDeref(dd, t1);
+ Cudd_RecursiveDeref(dd, u);
+ Cudd_RecursiveDeref(dd, w);
+ return(NULL);
+ }
+ cuddRef(t);
+ Cudd_RecursiveDeref(dd, w);
+ }
+ Cudd_RecursiveDeref(dd, u1);
+ Cudd_RecursiveDeref(dd, t1);
+ }
+
+ cuddDeref(u);
+ return(u);
+
+} /* end of addWalshInt */
diff --git a/src/bdd/cudd/cuddAndAbs.c b/src/bdd/cudd/cuddAndAbs.c
new file mode 100644
index 00000000..3a6ce85f
--- /dev/null
+++ b/src/bdd/cudd/cuddAndAbs.c
@@ -0,0 +1,306 @@
+/**CFile***********************************************************************
+
+ FileName [cuddAndAbs.c]
+
+ PackageName [cudd]
+
+ Synopsis [Combined AND and existential abstraction for BDDs]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_bddAndAbstract()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddBddAndAbstractRecur()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddAndAbs.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Takes the AND of two BDDs and simultaneously abstracts the
+ variables in cube.]
+
+ Description [Takes the AND of two BDDs and simultaneously abstracts
+ the variables in cube. The variables are existentially abstracted.
+ Returns a pointer to the result is successful; NULL otherwise.
+ Cudd_bddAndAbstract implements the semiring matrix multiplication
+ algorithm for the boolean semiring.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addMatrixMultiply Cudd_addTriangle Cudd_bddAnd]
+
+******************************************************************************/
+DdNode *
+Cudd_bddAndAbstract(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * g,
+ DdNode * cube)
+{
+ DdNode *res;
+
+ do {
+ manager->reordered = 0;
+ res = cuddBddAndAbstractRecur(manager, f, g, cube);
+ } while (manager->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddAndAbstract */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Takes the AND of two BDDs and simultaneously abstracts the
+ variables in cube.]
+
+ Description [Takes the AND of two BDDs and simultaneously abstracts
+ the variables in cube. The variables are existentially abstracted.
+ Returns a pointer to the result is successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddAndAbstract]
+
+******************************************************************************/
+DdNode *
+cuddBddAndAbstractRecur(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * g,
+ DdNode * cube)
+{
+ DdNode *F, *ft, *fe, *G, *gt, *ge;
+ DdNode *one, *zero, *r, *t, *e;
+ unsigned int topf, topg, topcube, top, index;
+
+ statLine(manager);
+ one = DD_ONE(manager);
+ zero = Cudd_Not(one);
+
+ /* Terminal cases. */
+ if (f == zero || g == zero || f == Cudd_Not(g)) return(zero);
+ if (f == one && g == one) return(one);
+
+ if (cube == one) {
+ return(cuddBddAndRecur(manager, f, g));
+ }
+ if (f == one || f == g) {
+ return(cuddBddExistAbstractRecur(manager, g, cube));
+ }
+ if (g == one) {
+ return(cuddBddExistAbstractRecur(manager, f, cube));
+ }
+ /* At this point f, g, and cube are not constant. */
+
+ if (f > g) { /* Try to increase cache efficiency. */
+ DdNode *tmp = f;
+ f = g;
+ g = tmp;
+ }
+
+ /* Here we can skip the use of cuddI, because the operands are known
+ ** to be non-constant.
+ */
+ F = Cudd_Regular(f);
+ G = Cudd_Regular(g);
+ topf = manager->perm[F->index];
+ topg = manager->perm[G->index];
+ top = ddMin(topf, topg);
+ topcube = manager->perm[cube->index];
+
+ while (topcube < top) {
+ cube = cuddT(cube);
+ if (cube == one) {
+ return(cuddBddAndRecur(manager, f, g));
+ }
+ topcube = manager->perm[cube->index];
+ }
+ /* Now, topcube >= top. */
+
+ /* Check cache. */
+ if (F->ref != 1 || G->ref != 1) {
+ r = cuddCacheLookup(manager, DD_BDD_AND_ABSTRACT_TAG, f, g, cube);
+ if (r != NULL) {
+ return(r);
+ }
+ }
+
+ if (topf == top) {
+ index = F->index;
+ ft = cuddT(F);
+ fe = cuddE(F);
+ if (Cudd_IsComplement(f)) {
+ ft = Cudd_Not(ft);
+ fe = Cudd_Not(fe);
+ }
+ } else {
+ index = G->index;
+ ft = fe = f;
+ }
+
+ if (topg == top) {
+ gt = cuddT(G);
+ ge = cuddE(G);
+ if (Cudd_IsComplement(g)) {
+ gt = Cudd_Not(gt);
+ ge = Cudd_Not(ge);
+ }
+ } else {
+ gt = ge = g;
+ }
+
+ if (topcube == top) { /* quantify */
+ DdNode *Cube = cuddT(cube);
+ t = cuddBddAndAbstractRecur(manager, ft, gt, Cube);
+ if (t == NULL) return(NULL);
+ /* Special case: 1 OR anything = 1. Hence, no need to compute
+ ** the else branch if t is 1. Likewise t + t * anything == t.
+ ** Notice that t == fe implies that fe does not depend on the
+ ** variables in Cube. Likewise for t == ge.
+ */
+ if (t == one || t == fe || t == ge) {
+ if (F->ref != 1 || G->ref != 1)
+ cuddCacheInsert(manager, DD_BDD_AND_ABSTRACT_TAG,
+ f, g, cube, t);
+ return(t);
+ }
+ cuddRef(t);
+ /* Special case: t + !t * anything == t + anything. */
+ if (t == Cudd_Not(fe)) {
+ e = cuddBddExistAbstractRecur(manager, ge, Cube);
+ } else if (t == Cudd_Not(ge)) {
+ e = cuddBddExistAbstractRecur(manager, fe, Cube);
+ } else {
+ e = cuddBddAndAbstractRecur(manager, fe, ge, Cube);
+ }
+ if (e == NULL) {
+ Cudd_IterDerefBdd(manager, t);
+ return(NULL);
+ }
+ if (t == e) {
+ r = t;
+ cuddDeref(t);
+ } else {
+ cuddRef(e);
+ r = cuddBddAndRecur(manager, Cudd_Not(t), Cudd_Not(e));
+ if (r == NULL) {
+ Cudd_IterDerefBdd(manager, t);
+ Cudd_IterDerefBdd(manager, e);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ cuddRef(r);
+ Cudd_DelayedDerefBdd(manager, t);
+ Cudd_DelayedDerefBdd(manager, e);
+ cuddDeref(r);
+ }
+ } else {
+ t = cuddBddAndAbstractRecur(manager, ft, gt, cube);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ e = cuddBddAndAbstractRecur(manager, fe, ge, cube);
+ if (e == NULL) {
+ Cudd_IterDerefBdd(manager, t);
+ return(NULL);
+ }
+ if (t == e) {
+ r = t;
+ cuddDeref(t);
+ } else {
+ cuddRef(e);
+ if (Cudd_IsComplement(t)) {
+ r = cuddUniqueInter(manager, (int) index,
+ Cudd_Not(t), Cudd_Not(e));
+ if (r == NULL) {
+ Cudd_IterDerefBdd(manager, t);
+ Cudd_IterDerefBdd(manager, e);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = cuddUniqueInter(manager,(int)index,t,e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(manager, t);
+ Cudd_IterDerefBdd(manager, e);
+ return(NULL);
+ }
+ }
+ cuddDeref(e);
+ cuddDeref(t);
+ }
+ }
+
+ if (F->ref != 1 || G->ref != 1)
+ cuddCacheInsert(manager, DD_BDD_AND_ABSTRACT_TAG, f, g, cube, r);
+ return (r);
+
+} /* end of cuddBddAndAbstractRecur */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
diff --git a/src/bdd/cudd/cuddAnneal.c b/src/bdd/cudd/cuddAnneal.c
new file mode 100644
index 00000000..dfc81e86
--- /dev/null
+++ b/src/bdd/cudd/cuddAnneal.c
@@ -0,0 +1,788 @@
+/**CFile***********************************************************************
+
+ FileName [cuddAnneal.c]
+
+ PackageName [cudd]
+
+ Synopsis [Reordering of DDs based on simulated annealing]
+
+ Description [Internal procedures included in this file:
+ <ul>
+ <li> cuddAnnealing()
+ </ul>
+ Static procedures included in this file:
+ <ul>
+ <li> stopping_criterion()
+ <li> random_generator()
+ <li> ddExchange()
+ <li> ddJumpingAux()
+ <li> ddJumpingUp()
+ <li> ddJumpingDown()
+ <li> siftBackwardProb()
+ <li> copyOrder()
+ <li> restoreOrder()
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [Jae-Young Jang, Jorgen Sivesind]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/* Annealing parameters */
+#define BETA 0.6
+#define ALPHA 0.90
+#define EXC_PROB 0.4
+#define JUMP_UP_PROB 0.36
+#define MAXGEN_RATIO 15.0
+#define STOP_TEMP 1.0
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddAnneal.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+#ifdef DD_STATS
+extern int ddTotalNumberSwapping;
+extern int ddTotalNISwaps;
+static int tosses;
+static int acceptances;
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int stopping_criterion ARGS((int c1, int c2, int c3, int c4, double temp));
+static double random_generator ARGS(());
+static int ddExchange ARGS((DdManager *table, int x, int y, double temp));
+static int ddJumpingAux ARGS((DdManager *table, int x, int x_low, int x_high, double temp));
+static Move * ddJumpingUp ARGS((DdManager *table, int x, int x_low, int initial_size));
+static Move * ddJumpingDown ARGS((DdManager *table, int x, int x_high, int initial_size));
+static int siftBackwardProb ARGS((DdManager *table, Move *moves, int size, double temp));
+static void copyOrder ARGS((DdManager *table, int *array, int lower, int upper));
+static int restoreOrder ARGS((DdManager *table, int *array, int lower, int upper));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Get new variable-order by simulated annealing algorithm.]
+
+ Description [Get x, y by random selection. Choose either
+ exchange or jump randomly. In case of jump, choose between jump_up
+ and jump_down randomly. Do exchange or jump and get optimal case.
+ Loop until there is no improvement or temperature reaches
+ minimum. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddAnnealing(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int nvars;
+ int size;
+ int x,y;
+ int result;
+ int c1, c2, c3, c4;
+ int BestCost;
+ int *BestOrder;
+ double NewTemp, temp;
+ double rand1;
+ int innerloop, maxGen;
+ int ecount, ucount, dcount;
+
+ nvars = upper - lower + 1;
+
+ result = cuddSifting(table,lower,upper);
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\n");
+#endif
+ if (result == 0) return(0);
+
+ size = table->keys - table->isolated;
+
+ /* Keep track of the best order. */
+ BestCost = size;
+ BestOrder = ALLOC(int,nvars);
+ if (BestOrder == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ copyOrder(table,BestOrder,lower,upper);
+
+ temp = BETA * size;
+ maxGen = (int) (MAXGEN_RATIO * nvars);
+
+ c1 = size + 10;
+ c2 = c1 + 10;
+ c3 = size;
+ c4 = c2 + 10;
+ ecount = ucount = dcount = 0;
+
+ while (!stopping_criterion(c1, c2, c3, c4, temp)) {
+#ifdef DD_STATS
+ (void) fprintf(table->out,"temp=%f\tsize=%d\tgen=%d\t",
+ temp,size,maxGen);
+ tosses = acceptances = 0;
+#endif
+ for (innerloop = 0; innerloop < maxGen; innerloop++) {
+ /* Choose x, y randomly. */
+ x = (int) Cudd_Random() % nvars;
+ do {
+ y = (int) Cudd_Random() % nvars;
+ } while (x == y);
+ x += lower;
+ y += lower;
+ if (x > y) {
+ int tmp = x;
+ x = y;
+ y = tmp;
+ }
+
+ /* Choose move with roulette wheel. */
+ rand1 = random_generator();
+ if (rand1 < EXC_PROB) {
+ result = ddExchange(table,x,y,temp); /* exchange */
+ ecount++;
+#if 0
+ (void) fprintf(table->out,
+ "Exchange of %d and %d: size = %d\n",
+ x,y,table->keys - table->isolated);
+#endif
+ } else if (rand1 < EXC_PROB + JUMP_UP_PROB) {
+ result = ddJumpingAux(table,y,x,y,temp); /* jumping_up */
+ ucount++;
+#if 0
+ (void) fprintf(table->out,
+ "Jump up of %d to %d: size = %d\n",
+ y,x,table->keys - table->isolated);
+#endif
+ } else {
+ result = ddJumpingAux(table,x,x,y,temp); /* jumping_down */
+ dcount++;
+#if 0
+ (void) fprintf(table->out,
+ "Jump down of %d to %d: size = %d\n",
+ x,y,table->keys - table->isolated);
+#endif
+ }
+
+ if (!result) {
+ FREE(BestOrder);
+ return(0);
+ }
+
+ size = table->keys - table->isolated; /* keep current size */
+ if (size < BestCost) { /* update best order */
+ BestCost = size;
+ copyOrder(table,BestOrder,lower,upper);
+ }
+ }
+ c1 = c2;
+ c2 = c3;
+ c3 = c4;
+ c4 = size;
+ NewTemp = ALPHA * temp;
+ if (NewTemp >= 1.0) {
+ maxGen = (int)(log(NewTemp) / log(temp) * maxGen);
+ }
+ temp = NewTemp; /* control variable */
+#ifdef DD_STATS
+ (void) fprintf(table->out,"uphill = %d\taccepted = %d\n",
+ tosses,acceptances);
+ fflush(table->out);
+#endif
+ }
+
+ result = restoreOrder(table,BestOrder,lower,upper);
+ FREE(BestOrder);
+ if (!result) return(0);
+#ifdef DD_STATS
+ fprintf(table->out,"#:N_EXCHANGE %8d : total exchanges\n",ecount);
+ fprintf(table->out,"#:N_JUMPUP %8d : total jumps up\n",ucount);
+ fprintf(table->out,"#:N_JUMPDOWN %8d : total jumps down",dcount);
+#endif
+ return(1);
+
+} /* end of cuddAnnealing */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Checks termination condition.]
+
+ Description [If temperature is STOP_TEMP or there is no improvement
+ then terminates. Returns 1 if the termination criterion is met; 0
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+stopping_criterion(
+ int c1,
+ int c2,
+ int c3,
+ int c4,
+ double temp)
+{
+ if (STOP_TEMP < temp) {
+ return(0);
+ } else if ((c1 == c2) && (c1 == c3) && (c1 == c4)) {
+ return(1);
+ } else {
+ return(0);
+ }
+
+} /* end of stopping_criterion */
+
+
+/**Function********************************************************************
+
+ Synopsis [Random number generator.]
+
+ Description [Returns a double precision value between 0.0 and 1.0.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static double
+random_generator(
+ )
+{
+ return((double)(Cudd_Random() / 2147483561.0));
+
+} /* end of random_generator */
+
+
+/**Function********************************************************************
+
+ Synopsis [This function is for exchanging two variables, x and y.]
+
+ Description [This is the same funcion as ddSwapping except for
+ comparison expression. Use probability function, exp(-size_change/temp).]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+ddExchange(
+ DdManager * table,
+ int x,
+ int y,
+ double temp)
+{
+ Move *move,*moves;
+ int tmp;
+ int x_ref,y_ref;
+ int x_next,y_next;
+ int size, result;
+ int initial_size, limit_size;
+
+ x_ref = x;
+ y_ref = y;
+
+ x_next = cuddNextHigh(table,x);
+ y_next = cuddNextLow(table,y);
+ moves = NULL;
+ initial_size = limit_size = table->keys - table->isolated;
+
+ for (;;) {
+ if (x_next == y_next) {
+ size = cuddSwapInPlace(table,x,x_next);
+ if (size == 0) goto ddExchangeOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddExchangeOutOfMem;
+ move->x = x;
+ move->y = x_next;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ size = cuddSwapInPlace(table,y_next,y);
+ if (size == 0) goto ddExchangeOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddExchangeOutOfMem;
+ move->x = y_next;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ size = cuddSwapInPlace(table,x,x_next);
+ if (size == 0) goto ddExchangeOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddExchangeOutOfMem;
+ move->x = x;
+ move->y = x_next;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+
+ tmp = x;
+ x = y;
+ y = tmp;
+ } else if (x == y_next) {
+ size = cuddSwapInPlace(table,x,x_next);
+ if (size == 0) goto ddExchangeOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddExchangeOutOfMem;
+ move->x = x;
+ move->y = x_next;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ tmp = x;
+ x = y;
+ y = tmp;
+ } else {
+ size = cuddSwapInPlace(table,x,x_next);
+ if (size == 0) goto ddExchangeOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddExchangeOutOfMem;
+ move->x = x;
+ move->y = x_next;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ size = cuddSwapInPlace(table,y_next,y);
+ if (size == 0) goto ddExchangeOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddExchangeOutOfMem;
+ move->x = y_next;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ x = x_next;
+ y = y_next;
+ }
+
+ x_next = cuddNextHigh(table,x);
+ y_next = cuddNextLow(table,y);
+ if (x_next > y_ref) break;
+
+ if ((double) size > DD_MAX_REORDER_GROWTH * (double) limit_size) {
+ break;
+ } else if (size < limit_size) {
+ limit_size = size;
+ }
+ }
+
+ if (y_next>=x_ref) {
+ size = cuddSwapInPlace(table,y_next,y);
+ if (size == 0) goto ddExchangeOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddExchangeOutOfMem;
+ move->x = y_next;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ }
+
+ /* move backward and stop at best position or accept uphill move */
+ result = siftBackwardProb(table,moves,initial_size,temp);
+ if (!result) goto ddExchangeOutOfMem;
+
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+ return(1);
+
+ddExchangeOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table,(DdNode *) moves);
+ moves = move;
+ }
+ return(0);
+
+} /* end of ddExchange */
+
+
+/**Function********************************************************************
+
+ Synopsis [Moves a variable to a specified position.]
+
+ Description [If x==x_low, it executes jumping_down. If x==x_high, it
+ executes jumping_up. This funcion is similar to ddSiftingAux. Returns
+ 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+ddJumpingAux(
+ DdManager * table,
+ int x,
+ int x_low,
+ int x_high,
+ double temp)
+{
+ Move *move;
+ Move *moves; /* list of moves */
+ int initial_size;
+ int result;
+
+ initial_size = table->keys - table->isolated;
+
+#ifdef DD_DEBUG
+ assert(table->subtables[x].keys > 0);
+#endif
+
+ moves = NULL;
+
+ if (cuddNextLow(table,x) < x_low) {
+ if (cuddNextHigh(table,x) > x_high) return(1);
+ moves = ddJumpingDown(table,x,x_high,initial_size);
+ /* after that point x --> x_high unless early termination */
+ if (moves == NULL) goto ddJumpingAuxOutOfMem;
+ /* move backward and stop at best position or accept uphill move */
+ result = siftBackwardProb(table,moves,initial_size,temp);
+ if (!result) goto ddJumpingAuxOutOfMem;
+ } else if (cuddNextHigh(table,x) > x_high) {
+ moves = ddJumpingUp(table,x,x_low,initial_size);
+ /* after that point x --> x_low unless early termination */
+ if (moves == NULL) goto ddJumpingAuxOutOfMem;
+ /* move backward and stop at best position or accept uphill move */
+ result = siftBackwardProb(table,moves,initial_size,temp);
+ if (!result) goto ddJumpingAuxOutOfMem;
+ } else {
+ (void) fprintf(table->err,"Unexpected condition in ddJumping\n");
+ goto ddJumpingAuxOutOfMem;
+ }
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+ return(1);
+
+ddJumpingAuxOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+ return(0);
+
+} /* end of ddJumpingAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [This function is for jumping up.]
+
+ Description [This is a simplified version of ddSiftingUp. It does not
+ use lower bounding. Returns the set of moves in case of success; NULL
+ if memory is full.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static Move *
+ddJumpingUp(
+ DdManager * table,
+ int x,
+ int x_low,
+ int initial_size)
+{
+ Move *moves;
+ Move *move;
+ int y;
+ int size;
+ int limit_size = initial_size;
+
+ moves = NULL;
+ y = cuddNextLow(table,x);
+ while (y >= x_low) {
+ size = cuddSwapInPlace(table,y,x);
+ if (size == 0) goto ddJumpingUpOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddJumpingUpOutOfMem;
+ move->x = y;
+ move->y = x;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ if ((double) size > table->maxGrowth * (double) limit_size) {
+ break;
+ } else if (size < limit_size) {
+ limit_size = size;
+ }
+ x = y;
+ y = cuddNextLow(table,x);
+ }
+ return(moves);
+
+ddJumpingUpOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+ return(NULL);
+
+} /* end of ddJumpingUp */
+
+
+/**Function********************************************************************
+
+ Synopsis [This function is for jumping down.]
+
+ Description [This is a simplified version of ddSiftingDown. It does not
+ use lower bounding. Returns the set of moves in case of success; NULL
+ if memory is full.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static Move *
+ddJumpingDown(
+ DdManager * table,
+ int x,
+ int x_high,
+ int initial_size)
+{
+ Move *moves;
+ Move *move;
+ int y;
+ int size;
+ int limit_size = initial_size;
+
+ moves = NULL;
+ y = cuddNextHigh(table,x);
+ while (y <= x_high) {
+ size = cuddSwapInPlace(table,x,y);
+ if (size == 0) goto ddJumpingDownOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddJumpingDownOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ if ((double) size > table->maxGrowth * (double) limit_size) {
+ break;
+ } else if (size < limit_size) {
+ limit_size = size;
+ }
+ x = y;
+ y = cuddNextHigh(table,x);
+ }
+ return(moves);
+
+ddJumpingDownOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+ return(NULL);
+
+} /* end of ddJumpingDown */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the DD to the best position encountered during
+ sifting if there was improvement.]
+
+ Description [Otherwise, "tosses a coin" to decide whether to keep
+ the current configuration or return the DD to the original
+ one. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+siftBackwardProb(
+ DdManager * table,
+ Move * moves,
+ int size,
+ double temp)
+{
+ Move *move;
+ int res;
+ int best_size = size;
+ double coin, threshold;
+
+ /* Look for best size during the last sifting */
+ for (move = moves; move != NULL; move = move->next) {
+ if (move->size < best_size) {
+ best_size = move->size;
+ }
+ }
+
+ /* If best_size equals size, the last sifting did not produce any
+ ** improvement. We now toss a coin to decide whether to retain
+ ** this change or not.
+ */
+ if (best_size == size) {
+ coin = random_generator();
+#ifdef DD_STATS
+ tosses++;
+#endif
+ threshold = exp(-((double)(table->keys - table->isolated - size))/temp);
+ if (coin < threshold) {
+#ifdef DD_STATS
+ acceptances++;
+#endif
+ return(1);
+ }
+ }
+
+ /* Either there was improvement, or we have decided not to
+ ** accept the uphill move. Go to best position.
+ */
+ res = table->keys - table->isolated;
+ for (move = moves; move != NULL; move = move->next) {
+ if (res == best_size) return(1);
+ res = cuddSwapInPlace(table,(int)move->x,(int)move->y);
+ if (!res) return(0);
+ }
+
+ return(1);
+
+} /* end of sift_backward_prob */
+
+
+/**Function********************************************************************
+
+ Synopsis [Copies the current variable order to array.]
+
+ Description [Copies the current variable order to array.
+ At the same time inverts the permutation.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+copyOrder(
+ DdManager * table,
+ int * array,
+ int lower,
+ int upper)
+{
+ int i;
+ int nvars;
+
+ nvars = upper - lower + 1;
+ for (i = 0; i < nvars; i++) {
+ array[i] = table->invperm[i+lower];
+ }
+
+} /* end of copyOrder */
+
+
+/**Function********************************************************************
+
+ Synopsis [Restores the variable order in array by a series of sifts up.]
+
+ Description [Restores the variable order in array by a series of sifts up.
+ Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+restoreOrder(
+ DdManager * table,
+ int * array,
+ int lower,
+ int upper)
+{
+ int i, x, y, size;
+ int nvars = upper - lower + 1;
+
+ for (i = 0; i < nvars; i++) {
+ x = table->perm[array[i]];
+#ifdef DD_DEBUG
+ assert(x >= lower && x <= upper);
+#endif
+ y = cuddNextLow(table,x);
+ while (y >= i + lower) {
+ size = cuddSwapInPlace(table,y,x);
+ if (size == 0) return(0);
+ x = y;
+ y = cuddNextLow(table,x);
+ }
+ }
+
+ return(1);
+
+} /* end of restoreOrder */
+
diff --git a/src/bdd/cudd/cuddApa.c b/src/bdd/cudd/cuddApa.c
new file mode 100644
index 00000000..805a4dde
--- /dev/null
+++ b/src/bdd/cudd/cuddApa.c
@@ -0,0 +1,930 @@
+/**CFile***********************************************************************
+
+ FileName [cuddApa.c]
+
+ PackageName [cudd]
+
+ Synopsis [Arbitrary precision arithmetic functions.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li>
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> ()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> ()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddApa.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+static DdNode *background, *zero;
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static DdApaNumber cuddApaCountMintermAux ARGS((DdNode * node, int digits, DdApaNumber max, DdApaNumber min, st_table * table));
+static enum st_retval cuddApaStCountfree ARGS((char * key, char * value, char * arg));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the number of digits for an arbitrary precision
+ integer.]
+
+ Description [Finds the number of digits for an arbitrary precision
+ integer given the maximum number of binary digits. The number of
+ binary digits should be positive. Returns the number of digits if
+ successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+Cudd_ApaNumberOfDigits(
+ int binaryDigits)
+{
+ int digits;
+
+ digits = binaryDigits / DD_APA_BITS;
+ if ((digits * DD_APA_BITS) != binaryDigits)
+ digits++;
+ return(digits);
+
+} /* end of Cudd_ApaNumberOfDigits */
+
+
+/**Function********************************************************************
+
+ Synopsis [Allocates memory for an arbitrary precision integer.]
+
+ Description [Allocates memory for an arbitrary precision
+ integer. Returns a pointer to the allocated memory if successful;
+ NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdApaNumber
+Cudd_NewApaNumber(
+ int digits)
+{
+ return(ALLOC(DdApaDigit, digits));
+
+} /* end of Cudd_NewApaNumber */
+
+
+/**Function********************************************************************
+
+ Synopsis [Makes a copy of an arbitrary precision integer.]
+
+ Description [Makes a copy of an arbitrary precision integer.]
+
+ SideEffects [Changes parameter <code>dest</code>.]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+Cudd_ApaCopy(
+ int digits,
+ DdApaNumber source,
+ DdApaNumber dest)
+{
+ int i;
+
+ for (i = 0; i < digits; i++) {
+ dest[i] = source[i];
+ }
+
+} /* end of Cudd_ApaCopy */
+
+
+/**Function********************************************************************
+
+ Synopsis [Adds two arbitrary precision integers.]
+
+ Description [Adds two arbitrary precision integers. Returns the
+ carry out of the most significant digit.]
+
+ SideEffects [The result of the sum is stored in parameter <code>sum</code>.]
+
+ SeeAlso []
+
+******************************************************************************/
+DdApaDigit
+Cudd_ApaAdd(
+ int digits,
+ DdApaNumber a,
+ DdApaNumber b,
+ DdApaNumber sum)
+{
+ int i;
+ DdApaDoubleDigit partial = 0;
+
+ for (i = digits - 1; i >= 0; i--) {
+ partial = a[i] + b[i] + DD_MSDIGIT(partial);
+ sum[i] = (DdApaDigit) DD_LSDIGIT(partial);
+ }
+ return(DD_MSDIGIT(partial));
+
+} /* end of Cudd_ApaAdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Subtracts two arbitrary precision integers.]
+
+ Description [Subtracts two arbitrary precision integers. Returns the
+ borrow out of the most significant digit.]
+
+ SideEffects [The result of the subtraction is stored in parameter
+ <code>diff</code>.]
+
+ SeeAlso []
+
+******************************************************************************/
+DdApaDigit
+Cudd_ApaSubtract(
+ int digits,
+ DdApaNumber a,
+ DdApaNumber b,
+ DdApaNumber diff)
+{
+ int i;
+ DdApaDoubleDigit partial = DD_APA_BASE;
+
+ for (i = digits - 1; i >= 0; i--) {
+ partial = a[i] - b[i] + DD_MSDIGIT(partial) + DD_APA_MASK;
+ diff[i] = (DdApaDigit) DD_LSDIGIT(partial);
+ }
+ return(DD_MSDIGIT(partial) - 1);
+
+} /* end of Cudd_ApaSubtract */
+
+
+/**Function********************************************************************
+
+ Synopsis [Divides an arbitrary precision integer by a digit.]
+
+ Description [Divides an arbitrary precision integer by a digit.]
+
+ SideEffects [The quotient is returned in parameter <code>quotient</code>.]
+
+ SeeAlso []
+
+******************************************************************************/
+DdApaDigit
+Cudd_ApaShortDivision(
+ int digits,
+ DdApaNumber dividend,
+ DdApaDigit divisor,
+ DdApaNumber quotient)
+{
+ int i;
+ DdApaDigit remainder;
+ DdApaDoubleDigit partial;
+
+ remainder = 0;
+ for (i = 0; i < digits; i++) {
+ partial = remainder * DD_APA_BASE + dividend[i];
+ quotient[i] = (DdApaDigit) (partial/(DdApaDoubleDigit)divisor);
+ remainder = (DdApaDigit) (partial % divisor);
+ }
+
+ return(remainder);
+
+} /* end of Cudd_ApaShortDivision */
+
+
+/**Function********************************************************************
+
+ Synopsis [Divides an arbitrary precision integer by an integer.]
+
+ Description [Divides an arbitrary precision integer by a 32-bit
+ unsigned integer. Returns the remainder of the division. This
+ procedure relies on the assumption that the number of bits of a
+ DdApaDigit plus the number of bits of an unsigned int is less the
+ number of bits of the mantissa of a double. This guarantees that the
+ product of a DdApaDigit and an unsigned int can be represented
+ without loss of precision by a double. On machines where this
+ assumption is not satisfied, this procedure will malfunction.]
+
+ SideEffects [The quotient is returned in parameter <code>quotient</code>.]
+
+ SeeAlso [Cudd_ApaShortDivision]
+
+******************************************************************************/
+unsigned int
+Cudd_ApaIntDivision(
+ int digits,
+ DdApaNumber dividend,
+ unsigned int divisor,
+ DdApaNumber quotient)
+{
+ int i;
+ double partial;
+ unsigned int remainder = 0;
+ double ddiv = (double) divisor;
+
+ for (i = 0; i < digits; i++) {
+ partial = (double) remainder * DD_APA_BASE + dividend[i];
+ quotient[i] = (DdApaDigit) (partial / ddiv);
+ remainder = (unsigned int) (partial - ((double)quotient[i] * ddiv));
+ }
+
+ return(remainder);
+
+} /* end of Cudd_ApaIntDivision */
+
+
+/**Function********************************************************************
+
+ Synopsis [Shifts right an arbitrary precision integer by one binary
+ place.]
+
+ Description [Shifts right an arbitrary precision integer by one
+ binary place. The most significant binary digit of the result is
+ taken from parameter <code>in</code>.]
+
+ SideEffects [The result is returned in parameter <code>b</code>.]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+Cudd_ApaShiftRight(
+ int digits,
+ DdApaDigit in,
+ DdApaNumber a,
+ DdApaNumber b)
+{
+ int i;
+
+ for (i = digits - 1; i > 0; i--) {
+ b[i] = (a[i] >> 1) | ((a[i-1] & 1) << (DD_APA_BITS - 1));
+ }
+ b[0] = (a[0] >> 1) | (in << (DD_APA_BITS - 1));
+
+} /* end of Cudd_ApaShiftRight */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets an arbitrary precision integer to a one-digit literal.]
+
+ Description [Sets an arbitrary precision integer to a one-digit literal.]
+
+ SideEffects [The result is returned in parameter <code>number</code>.]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+Cudd_ApaSetToLiteral(
+ int digits,
+ DdApaNumber number,
+ DdApaDigit literal)
+{
+ int i;
+
+ for (i = 0; i < digits - 1; i++)
+ number[i] = 0;
+ number[digits - 1] = literal;
+
+} /* end of Cudd_ApaSetToLiteral */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets an arbitrary precision integer to a power of two.]
+
+ Description [Sets an arbitrary precision integer to a power of
+ two. If the power of two is too large to be represented, the number
+ is set to 0.]
+
+ SideEffects [The result is returned in parameter <code>number</code>.]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+Cudd_ApaPowerOfTwo(
+ int digits,
+ DdApaNumber number,
+ int power)
+{
+ int i;
+ int index;
+
+ for (i = 0; i < digits; i++)
+ number[i] = 0;
+ i = digits - 1 - power / DD_APA_BITS;
+ if (i < 0) return;
+ index = power & (DD_APA_BITS - 1);
+ number[i] = 1 << index;
+
+} /* end of Cudd_ApaPowerOfTwo */
+
+
+/**Function********************************************************************
+
+ Synopsis [Compares two arbitrary precision integers.]
+
+ Description [Compares two arbitrary precision integers. Returns 1 if
+ the first number is larger; 0 if they are equal; -1 if the second
+ number is larger.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+Cudd_ApaCompare(
+ int digitsFirst,
+ DdApaNumber first,
+ int digitsSecond,
+ DdApaNumber second)
+{
+ int i;
+ int firstNZ, secondNZ;
+
+ /* Find first non-zero in both numbers. */
+ for (firstNZ = 0; firstNZ < digitsFirst; firstNZ++)
+ if (first[firstNZ] != 0) break;
+ for (secondNZ = 0; secondNZ < digitsSecond; secondNZ++)
+ if (second[secondNZ] != 0) break;
+ if (digitsFirst - firstNZ > digitsSecond - secondNZ) return(1);
+ else if (digitsFirst - firstNZ < digitsSecond - secondNZ) return(-1);
+ for (i = 0; i < digitsFirst - firstNZ; i++) {
+ if (first[firstNZ + i] > second[secondNZ + i]) return(1);
+ else if (first[firstNZ + i] < second[secondNZ + i]) return(-1);
+ }
+ return(0);
+
+} /* end of Cudd_ApaCompare */
+
+
+/**Function********************************************************************
+
+ Synopsis [Compares the ratios of two arbitrary precision integers to two
+ unsigned ints.]
+
+ Description [Compares the ratios of two arbitrary precision integers
+ to two unsigned ints. Returns 1 if the first number is larger; 0 if
+ they are equal; -1 if the second number is larger.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+Cudd_ApaCompareRatios(
+ int digitsFirst,
+ DdApaNumber firstNum,
+ unsigned int firstDen,
+ int digitsSecond,
+ DdApaNumber secondNum,
+ unsigned int secondDen)
+{
+ int result;
+ DdApaNumber first, second;
+ unsigned int firstRem, secondRem;
+
+ first = Cudd_NewApaNumber(digitsFirst);
+ firstRem = Cudd_ApaIntDivision(digitsFirst,firstNum,firstDen,first);
+ second = Cudd_NewApaNumber(digitsSecond);
+ secondRem = Cudd_ApaIntDivision(digitsSecond,secondNum,secondDen,second);
+ result = Cudd_ApaCompare(digitsFirst,first,digitsSecond,second);
+ if (result == 0) {
+ if ((double)firstRem/firstDen > (double)secondRem/secondDen)
+ return(1);
+ else if ((double)firstRem/firstDen < (double)secondRem/secondDen)
+ return(-1);
+ }
+ return(result);
+
+} /* end of Cudd_ApaCompareRatios */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints an arbitrary precision integer in hexadecimal format.]
+
+ Description [Prints an arbitrary precision integer in hexadecimal format.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ApaPrintDecimal Cudd_ApaPrintExponential]
+
+******************************************************************************/
+int
+Cudd_ApaPrintHex(
+ FILE * fp,
+ int digits,
+ DdApaNumber number)
+{
+ int i, result;
+
+ for (i = 0; i < digits; i++) {
+ result = fprintf(fp,DD_APA_HEXPRINT,number[i]);
+ if (result == EOF)
+ return(0);
+ }
+ return(1);
+
+} /* end of Cudd_ApaPrintHex */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints an arbitrary precision integer in decimal format.]
+
+ Description [Prints an arbitrary precision integer in decimal format.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ApaPrintHex Cudd_ApaPrintExponential]
+
+******************************************************************************/
+int
+Cudd_ApaPrintDecimal(
+ FILE * fp,
+ int digits,
+ DdApaNumber number)
+{
+ int i, result;
+ DdApaDigit remainder;
+ DdApaNumber work;
+ unsigned char *decimal;
+ int leadingzero;
+ int decimalDigits = (int) (digits * log10((double) DD_APA_BASE)) + 1;
+
+ work = Cudd_NewApaNumber(digits);
+ if (work == NULL)
+ return(0);
+ decimal = ALLOC(unsigned char, decimalDigits);
+ if (decimal == NULL) {
+ FREE(work);
+ return(0);
+ }
+ Cudd_ApaCopy(digits,number,work);
+ for (i = decimalDigits - 1; i >= 0; i--) {
+ remainder = Cudd_ApaShortDivision(digits,work,(DdApaDigit) 10,work);
+ decimal[i] = remainder;
+ }
+ FREE(work);
+
+ leadingzero = 1;
+ for (i = 0; i < decimalDigits; i++) {
+ leadingzero = leadingzero && (decimal[i] == 0);
+ if ((!leadingzero) || (i == (decimalDigits - 1))) {
+ result = fprintf(fp,"%1d",decimal[i]);
+ if (result == EOF) {
+ FREE(decimal);
+ return(0);
+ }
+ }
+ }
+ FREE(decimal);
+ return(1);
+
+} /* end of Cudd_ApaPrintDecimal */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints an arbitrary precision integer in exponential format.]
+
+ Description [Prints an arbitrary precision integer in exponential format.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ApaPrintHex Cudd_ApaPrintDecimal]
+
+******************************************************************************/
+int
+Cudd_ApaPrintExponential(
+ FILE * fp,
+ int digits,
+ DdApaNumber number,
+ int precision)
+{
+ int i, first, last, result;
+ DdApaDigit remainder;
+ DdApaNumber work;
+ unsigned char *decimal;
+ int decimalDigits = (int) (digits * log10((double) DD_APA_BASE)) + 1;
+
+ work = Cudd_NewApaNumber(digits);
+ if (work == NULL)
+ return(0);
+ decimal = ALLOC(unsigned char, decimalDigits);
+ if (decimal == NULL) {
+ FREE(work);
+ return(0);
+ }
+ Cudd_ApaCopy(digits,number,work);
+ first = decimalDigits - 1;
+ for (i = decimalDigits - 1; i >= 0; i--) {
+ remainder = Cudd_ApaShortDivision(digits,work,(DdApaDigit) 10,work);
+ decimal[i] = remainder;
+ if (remainder != 0) first = i; /* keep track of MS non-zero */
+ }
+ FREE(work);
+ last = ddMin(first + precision, decimalDigits);
+
+ for (i = first; i < last; i++) {
+ result = fprintf(fp,"%s%1d",i == first+1 ? "." : "", decimal[i]);
+ if (result == EOF) {
+ FREE(decimal);
+ return(0);
+ }
+ }
+ FREE(decimal);
+ result = fprintf(fp,"e+%d",decimalDigits - first - 1);
+ if (result == EOF) {
+ return(0);
+ }
+ return(1);
+
+} /* end of Cudd_ApaPrintExponential */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the number of minterms of a DD.]
+
+ Description [Counts the number of minterms of a DD. The function is
+ assumed to depend on nvars variables. The minterm count is
+ represented as an arbitrary precision unsigned integer, to allow for
+ any number of variables CUDD supports. Returns a pointer to the
+ array representing the number of minterms of the function rooted at
+ node if successful; NULL otherwise.]
+
+ SideEffects [The number of digits of the result is returned in
+ parameter <code>digits</code>.]
+
+ SeeAlso [Cudd_CountMinterm]
+
+******************************************************************************/
+DdApaNumber
+Cudd_ApaCountMinterm(
+ DdManager * manager,
+ DdNode * node,
+ int nvars,
+ int * digits)
+{
+ DdApaNumber max, min;
+ st_table *table;
+ DdApaNumber i,count;
+
+ background = manager->background;
+ zero = Cudd_Not(manager->one);
+
+ *digits = Cudd_ApaNumberOfDigits(nvars+1);
+ max = Cudd_NewApaNumber(*digits);
+ if (max == NULL) {
+ return(NULL);
+ }
+ Cudd_ApaPowerOfTwo(*digits,max,nvars);
+ min = Cudd_NewApaNumber(*digits);
+ if (min == NULL) {
+ FREE(max);
+ return(NULL);
+ }
+ Cudd_ApaSetToLiteral(*digits,min,0);
+ table = st_init_table(st_ptrcmp,st_ptrhash);
+ if (table == NULL) {
+ FREE(max);
+ FREE(min);
+ return(NULL);
+ }
+ i = cuddApaCountMintermAux(Cudd_Regular(node),*digits,max,min,table);
+ if (i == NULL) {
+ FREE(max);
+ FREE(min);
+ st_foreach(table, cuddApaStCountfree, NULL);
+ st_free_table(table);
+ return(NULL);
+ }
+ count = Cudd_NewApaNumber(*digits);
+ if (count == NULL) {
+ FREE(max);
+ FREE(min);
+ st_foreach(table, cuddApaStCountfree, NULL);
+ st_free_table(table);
+ if (Cudd_Regular(node)->ref == 1) FREE(i);
+ return(NULL);
+ }
+ if (Cudd_IsComplement(node)) {
+ (void) Cudd_ApaSubtract(*digits,max,i,count);
+ } else {
+ Cudd_ApaCopy(*digits,i,count);
+ }
+ FREE(max);
+ FREE(min);
+ st_foreach(table, cuddApaStCountfree, NULL);
+ st_free_table(table);
+ if (Cudd_Regular(node)->ref == 1) FREE(i);
+ return(count);
+
+} /* end of Cudd_ApaCountMinterm */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints the number of minterms of a BDD or ADD using
+ arbitrary precision arithmetic.]
+
+ Description [Prints the number of minterms of a BDD or ADD using
+ arbitrary precision arithmetic. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ApaPrintMintermExp]
+
+******************************************************************************/
+int
+Cudd_ApaPrintMinterm(
+ FILE * fp,
+ DdManager * dd,
+ DdNode * node,
+ int nvars)
+{
+ int digits;
+ int result;
+ DdApaNumber count;
+
+ count = Cudd_ApaCountMinterm(dd,node,nvars,&digits);
+ if (count == NULL)
+ return(0);
+ result = Cudd_ApaPrintDecimal(fp,digits,count);
+ FREE(count);
+ if (fprintf(fp,"\n") == EOF) {
+ return(0);
+ }
+ return(result);
+
+} /* end of Cudd_ApaPrintMinterm */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints the number of minterms of a BDD or ADD in exponential
+ format using arbitrary precision arithmetic.]
+
+ Description [Prints the number of minterms of a BDD or ADD in
+ exponential format using arbitrary precision arithmetic. Parameter
+ precision controls the number of signficant digits printed. Returns
+ 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ApaPrintMinterm]
+
+******************************************************************************/
+int
+Cudd_ApaPrintMintermExp(
+ FILE * fp,
+ DdManager * dd,
+ DdNode * node,
+ int nvars,
+ int precision)
+{
+ int digits;
+ int result;
+ DdApaNumber count;
+
+ count = Cudd_ApaCountMinterm(dd,node,nvars,&digits);
+ if (count == NULL)
+ return(0);
+ result = Cudd_ApaPrintExponential(fp,digits,count,precision);
+ FREE(count);
+ if (fprintf(fp,"\n") == EOF) {
+ return(0);
+ }
+ return(result);
+
+} /* end of Cudd_ApaPrintMintermExp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints the density of a BDD or ADD using
+ arbitrary precision arithmetic.]
+
+ Description [Prints the density of a BDD or ADD using
+ arbitrary precision arithmetic. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+Cudd_ApaPrintDensity(
+ FILE * fp,
+ DdManager * dd,
+ DdNode * node,
+ int nvars)
+{
+ int digits;
+ int result;
+ DdApaNumber count,density;
+ unsigned int size, remainder, fractional;
+
+ count = Cudd_ApaCountMinterm(dd,node,nvars,&digits);
+ if (count == NULL)
+ return(0);
+ size = Cudd_DagSize(node);
+ density = Cudd_NewApaNumber(digits);
+ remainder = Cudd_ApaIntDivision(digits,count,size,density);
+ result = Cudd_ApaPrintDecimal(fp,digits,density);
+ FREE(count);
+ FREE(density);
+ fractional = (unsigned int)((double)remainder / size * 1000000);
+ if (fprintf(fp,".%u\n", fractional) == EOF) {
+ return(0);
+ }
+ return(result);
+
+} /* end of Cudd_ApaPrintDensity */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_ApaCountMinterm.]
+
+ Description [Performs the recursive step of Cudd_ApaCountMinterm.
+ It is based on the following identity. Let |f| be the
+ number of minterms of f. Then:
+ <xmp>
+ |f| = (|f0|+|f1|)/2
+ </xmp>
+ where f0 and f1 are the two cofactors of f.
+ Uses the identity <code>|f'| = max - |f|</code>.
+ The procedure expects the argument "node" to be a regular pointer, and
+ guarantees this condition is met in the recursive calls.
+ For efficiency, the result of a call is cached only if the node has
+ a reference count greater than 1.
+ Returns the number of minterms of the function rooted at node.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static DdApaNumber
+cuddApaCountMintermAux(
+ DdNode * node,
+ int digits,
+ DdApaNumber max,
+ DdApaNumber min,
+ st_table * table)
+{
+ DdNode *Nt, *Ne;
+ DdApaNumber mint, mint1, mint2;
+ DdApaDigit carryout;
+
+ if (cuddIsConstant(node)) {
+ if (node == background || node == zero) {
+ return(min);
+ } else {
+ return(max);
+ }
+ }
+ if (node->ref > 1 && st_lookup(table, (char *)node, (char **)&mint)) {
+ return(mint);
+ }
+
+ Nt = cuddT(node); Ne = cuddE(node);
+
+ mint1 = cuddApaCountMintermAux(Nt, digits, max, min, table);
+ if (mint1 == NULL) return(NULL);
+ mint2 = cuddApaCountMintermAux(Cudd_Regular(Ne), digits, max, min, table);
+ if (mint2 == NULL) {
+ if (Nt->ref == 1) FREE(mint1);
+ return(NULL);
+ }
+ mint = Cudd_NewApaNumber(digits);
+ if (mint == NULL) {
+ if (Nt->ref == 1) FREE(mint1);
+ if (Cudd_Regular(Ne)->ref == 1) FREE(mint2);
+ return(NULL);
+ }
+ if (Cudd_IsComplement(Ne)) {
+ (void) Cudd_ApaSubtract(digits,max,mint2,mint);
+ carryout = Cudd_ApaAdd(digits,mint1,mint,mint);
+ } else {
+ carryout = Cudd_ApaAdd(digits,mint1,mint2,mint);
+ }
+ Cudd_ApaShiftRight(digits,carryout,mint,mint);
+ /* If the refernce count of a child is 1, its minterm count
+ ** hasn't been stored in table. Therefore, it must be explicitly
+ ** freed here. */
+ if (Nt->ref == 1) FREE(mint1);
+ if (Cudd_Regular(Ne)->ref == 1) FREE(mint2);
+
+ if (node->ref > 1) {
+ if (st_insert(table, (char *)node, (char *)mint) == ST_OUT_OF_MEM) {
+ FREE(mint);
+ return(NULL);
+ }
+ }
+ return(mint);
+
+} /* end of cuddApaCountMintermAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees the memory used to store the minterm counts recorded
+ in the visited table.]
+
+ Description [Frees the memory used to store the minterm counts
+ recorded in the visited table. Returns ST_CONTINUE.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static enum st_retval
+cuddApaStCountfree(
+ char * key,
+ char * value,
+ char * arg)
+{
+ DdApaNumber d;
+
+ d = (DdApaNumber) value;
+ FREE(d);
+ return(ST_CONTINUE);
+
+} /* end of cuddApaStCountfree */
+
+
diff --git a/src/bdd/cudd/cuddApprox.c b/src/bdd/cudd/cuddApprox.c
new file mode 100644
index 00000000..eb6813ff
--- /dev/null
+++ b/src/bdd/cudd/cuddApprox.c
@@ -0,0 +1,2192 @@
+/**CFile***********************************************************************
+
+ FileName [cuddApprox.c]
+
+ PackageName [cudd]
+
+ Synopsis [Procedures to approximate a given BDD.]
+
+ Description [External procedures provided by this module:
+ <ul>
+ <li> Cudd_UnderApprox()
+ <li> Cudd_OverApprox()
+ <li> Cudd_RemapUnderApprox()
+ <li> Cudd_RemapOverApprox()
+ <li> Cudd_BiasedUnderApprox()
+ <li> Cudd_BiasedOverApprox()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddUnderApprox()
+ <li> cuddRemapUnderApprox()
+ <li> cuddBiasedUnderApprox()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> gatherInfoAux()
+ <li> gatherInfo()
+ <li> computeSavings()
+ <li> UAmarkNodes()
+ <li> UAbuildSubset()
+ <li> updateRefs()
+ <li> RAmarkNodes()
+ <li> BAmarkNodes()
+ <li> RAbuildSubset()
+ </ul>
+ ]
+
+ SeeAlso [cuddSubsetHB.c cuddSubsetSP.c cuddGenCof.c]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no
+ warranty about the suitability of this software for any
+ purpose. It is presented on an AS IS basis.]
+
+******************************************************************************/
+
+#ifdef __STDC__
+#include <float.h>
+#else
+#define DBL_MAX_EXP 1024
+#endif
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define NOTHING 0
+#define REPLACE_T 1
+#define REPLACE_E 2
+#define REPLACE_N 3
+#define REPLACE_TT 4
+#define REPLACE_TE 5
+
+#define DONT_CARE 0
+#define CARE 1
+#define TOTAL_CARE 2
+#define CARE_ERROR 3
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/* Data structure to store the information on each node. It keeps the
+** number of minterms of the function rooted at this node in terms of
+** the number of variables specified by the user; the number of
+** minterms of the complement; the impact of the number of minterms of
+** this function on the number of minterms of the root function; the
+** reference count of the node from within the root function; the
+** reference count of the node from an internal node; and the flag
+** that says whether the node should be replaced and how. */
+typedef struct NodeData {
+ double mintermsP; /* minterms for the regular node */
+ double mintermsN; /* minterms for the complemented node */
+ int functionRef; /* references from within this function */
+ char care; /* node intersects care set */
+ char replace; /* replacement decision */
+ short int parity; /* 1: even; 2: odd; 3: both */
+ DdNode *resultP; /* result for even parity */
+ DdNode *resultN; /* result for odd parity */
+} NodeData;
+
+typedef struct ApproxInfo {
+ DdNode *one; /* one constant */
+ DdNode *zero; /* BDD zero constant */
+ NodeData *page; /* per-node information */
+ st_table *table; /* hash table to access the per-node info */
+ int index; /* index of the current node */
+ double max; /* max number of minterms */
+ int size; /* how many nodes are left */
+ double minterms; /* how many minterms are left */
+} ApproxInfo;
+
+/* Item of the queue used in the levelized traversal of the BDD. */
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+typedef struct GlobalQueueItem {
+ struct GlobalQueueItem *next;
+ struct GlobalQueueItem *cnext;
+ DdNode *node;
+ double impactP;
+ double impactN;
+} GlobalQueueItem;
+
+typedef struct LocalQueueItem {
+ struct LocalQueueItem *next;
+ struct LocalQueueItem *cnext;
+ DdNode *node;
+ int localRef;
+} LocalQueueItem;
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddApprox.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static void updateParity ARGS((DdNode *node, ApproxInfo *info, int newparity));
+static NodeData * gatherInfoAux ARGS((DdNode *node, ApproxInfo *info, int parity));
+static ApproxInfo * gatherInfo ARGS((DdManager *dd, DdNode *node, int numVars, int parity));
+static int computeSavings ARGS((DdManager *dd, DdNode *f, DdNode *skip, ApproxInfo *info, DdLevelQueue *queue));
+static int updateRefs ARGS((DdManager *dd, DdNode *f, DdNode *skip, ApproxInfo *info, DdLevelQueue *queue));
+static int UAmarkNodes ARGS((DdManager *dd, DdNode *f, ApproxInfo *info, int threshold, int safe, double quality));
+static DdNode * UAbuildSubset ARGS((DdManager *dd, DdNode *node, ApproxInfo *info));
+static int RAmarkNodes ARGS((DdManager *dd, DdNode *f, ApproxInfo *info, int threshold, double quality));
+static int BAmarkNodes ARGS((DdManager *dd, DdNode *f, ApproxInfo *info, int threshold, double quality1, double quality0));
+static DdNode * RAbuildSubset ARGS((DdManager *dd, DdNode *node, ApproxInfo *info));
+static int BAapplyBias ARGS((DdManager *dd, DdNode *f, DdNode *b, ApproxInfo *info, DdHashTable *cache));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Extracts a dense subset from a BDD with Shiple's
+ underapproximation method.]
+
+ Description [Extracts a dense subset from a BDD. This procedure uses
+ a variant of Tom Shiple's underapproximation method. The main
+ difference from the original method is that density is used as cost
+ function. Returns a pointer to the BDD of the subset if
+ successful. NULL if the procedure runs out of memory. The parameter
+ numVars is the maximum number of variables to be used in minterm
+ calculation. The optimal number should be as close as possible to
+ the size of the support of f. However, it is safe to pass the value
+ returned by Cudd_ReadSize for numVars when the number of variables
+ is under 1023. If numVars is larger than 1023, it will cause
+ overflow. If a 0 parameter is passed then the procedure will compute
+ a value which will avoid overflow but will cause underflow with 2046
+ variables or more.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SubsetShortPaths Cudd_SubsetHeavyBranch Cudd_ReadSize]
+
+******************************************************************************/
+DdNode *
+Cudd_UnderApprox(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be subset */,
+ int numVars /* number of variables in the support of f */,
+ int threshold /* when to stop approximation */,
+ int safe /* enforce safe approximation */,
+ double quality /* minimum improvement for accepted changes */)
+{
+ DdNode *subset;
+
+ do {
+ dd->reordered = 0;
+ subset = cuddUnderApprox(dd, f, numVars, threshold, safe, quality);
+ } while (dd->reordered == 1);
+
+ return(subset);
+
+} /* end of Cudd_UnderApprox */
+
+
+/**Function********************************************************************
+
+ Synopsis [Extracts a dense superset from a BDD with Shiple's
+ underapproximation method.]
+
+ Description [Extracts a dense superset from a BDD. The procedure is
+ identical to the underapproximation procedure except for the fact that it
+ works on the complement of the given function. Extracting the subset
+ of the complement function is equivalent to extracting the superset
+ of the function.
+ Returns a pointer to the BDD of the superset if successful. NULL if
+ intermediate result causes the procedure to run out of memory. The
+ parameter numVars is the maximum number of variables to be used in
+ minterm calculation. The optimal number
+ should be as close as possible to the size of the support of f.
+ However, it is safe to pass the value returned by Cudd_ReadSize for
+ numVars when the number of variables is under 1023. If numVars is
+ larger than 1023, it will overflow. If a 0 parameter is passed then
+ the procedure will compute a value which will avoid overflow but
+ will cause underflow with 2046 variables or more.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SupersetHeavyBranch Cudd_SupersetShortPaths Cudd_ReadSize]
+
+******************************************************************************/
+DdNode *
+Cudd_OverApprox(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be superset */,
+ int numVars /* number of variables in the support of f */,
+ int threshold /* when to stop approximation */,
+ int safe /* enforce safe approximation */,
+ double quality /* minimum improvement for accepted changes */)
+{
+ DdNode *subset, *g;
+
+ g = Cudd_Not(f);
+ do {
+ dd->reordered = 0;
+ subset = cuddUnderApprox(dd, g, numVars, threshold, safe, quality);
+ } while (dd->reordered == 1);
+
+ return(Cudd_NotCond(subset, (subset != NULL)));
+
+} /* end of Cudd_OverApprox */
+
+
+/**Function********************************************************************
+
+ Synopsis [Extracts a dense subset from a BDD with the remapping
+ underapproximation method.]
+
+ Description [Extracts a dense subset from a BDD. This procedure uses
+ a remapping technique and density as the cost function.
+ Returns a pointer to the BDD of the subset if
+ successful. NULL if the procedure runs out of memory. The parameter
+ numVars is the maximum number of variables to be used in minterm
+ calculation. The optimal number should be as close as possible to
+ the size of the support of f. However, it is safe to pass the value
+ returned by Cudd_ReadSize for numVars when the number of variables
+ is under 1023. If numVars is larger than 1023, it will cause
+ overflow. If a 0 parameter is passed then the procedure will compute
+ a value which will avoid overflow but will cause underflow with 2046
+ variables or more.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SubsetShortPaths Cudd_SubsetHeavyBranch Cudd_UnderApprox Cudd_ReadSize]
+
+******************************************************************************/
+DdNode *
+Cudd_RemapUnderApprox(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be subset */,
+ int numVars /* number of variables in the support of f */,
+ int threshold /* when to stop approximation */,
+ double quality /* minimum improvement for accepted changes */)
+{
+ DdNode *subset;
+
+ do {
+ dd->reordered = 0;
+ subset = cuddRemapUnderApprox(dd, f, numVars, threshold, quality);
+ } while (dd->reordered == 1);
+
+ return(subset);
+
+} /* end of Cudd_RemapUnderApprox */
+
+
+/**Function********************************************************************
+
+ Synopsis [Extracts a dense superset from a BDD with the remapping
+ underapproximation method.]
+
+ Description [Extracts a dense superset from a BDD. The procedure is
+ identical to the underapproximation procedure except for the fact that it
+ works on the complement of the given function. Extracting the subset
+ of the complement function is equivalent to extracting the superset
+ of the function.
+ Returns a pointer to the BDD of the superset if successful. NULL if
+ intermediate result causes the procedure to run out of memory. The
+ parameter numVars is the maximum number of variables to be used in
+ minterm calculation. The optimal number
+ should be as close as possible to the size of the support of f.
+ However, it is safe to pass the value returned by Cudd_ReadSize for
+ numVars when the number of variables is under 1023. If numVars is
+ larger than 1023, it will overflow. If a 0 parameter is passed then
+ the procedure will compute a value which will avoid overflow but
+ will cause underflow with 2046 variables or more.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SupersetHeavyBranch Cudd_SupersetShortPaths Cudd_ReadSize]
+
+******************************************************************************/
+DdNode *
+Cudd_RemapOverApprox(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be superset */,
+ int numVars /* number of variables in the support of f */,
+ int threshold /* when to stop approximation */,
+ double quality /* minimum improvement for accepted changes */)
+{
+ DdNode *subset, *g;
+
+ g = Cudd_Not(f);
+ do {
+ dd->reordered = 0;
+ subset = cuddRemapUnderApprox(dd, g, numVars, threshold, quality);
+ } while (dd->reordered == 1);
+
+ return(Cudd_NotCond(subset, (subset != NULL)));
+
+} /* end of Cudd_RemapOverApprox */
+
+
+/**Function********************************************************************
+
+ Synopsis [Extracts a dense subset from a BDD with the biased
+ underapproximation method.]
+
+ Description [Extracts a dense subset from a BDD. This procedure uses
+ a biased remapping technique and density as the cost function. The bias
+ is a function. This procedure tries to approximate where the bias is 0
+ and preserve the given function where the bias is 1.
+ Returns a pointer to the BDD of the subset if
+ successful. NULL if the procedure runs out of memory. The parameter
+ numVars is the maximum number of variables to be used in minterm
+ calculation. The optimal number should be as close as possible to
+ the size of the support of f. However, it is safe to pass the value
+ returned by Cudd_ReadSize for numVars when the number of variables
+ is under 1023. If numVars is larger than 1023, it will cause
+ overflow. If a 0 parameter is passed then the procedure will compute
+ a value which will avoid overflow but will cause underflow with 2046
+ variables or more.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SubsetShortPaths Cudd_SubsetHeavyBranch Cudd_UnderApprox
+ Cudd_RemapUnderApprox Cudd_ReadSize]
+
+******************************************************************************/
+DdNode *
+Cudd_BiasedUnderApprox(
+ DdManager *dd /* manager */,
+ DdNode *f /* function to be subset */,
+ DdNode *b /* bias function */,
+ int numVars /* number of variables in the support of f */,
+ int threshold /* when to stop approximation */,
+ double quality1 /* minimum improvement for accepted changes when b=1 */,
+ double quality0 /* minimum improvement for accepted changes when b=0 */)
+{
+ DdNode *subset;
+
+ do {
+ dd->reordered = 0;
+ subset = cuddBiasedUnderApprox(dd, f, b, numVars, threshold, quality1,
+ quality0);
+ } while (dd->reordered == 1);
+
+ return(subset);
+
+} /* end of Cudd_BiasedUnderApprox */
+
+
+/**Function********************************************************************
+
+ Synopsis [Extracts a dense superset from a BDD with the biased
+ underapproximation method.]
+
+ Description [Extracts a dense superset from a BDD. The procedure is
+ identical to the underapproximation procedure except for the fact that it
+ works on the complement of the given function. Extracting the subset
+ of the complement function is equivalent to extracting the superset
+ of the function.
+ Returns a pointer to the BDD of the superset if successful. NULL if
+ intermediate result causes the procedure to run out of memory. The
+ parameter numVars is the maximum number of variables to be used in
+ minterm calculation. The optimal number
+ should be as close as possible to the size of the support of f.
+ However, it is safe to pass the value returned by Cudd_ReadSize for
+ numVars when the number of variables is under 1023. If numVars is
+ larger than 1023, it will overflow. If a 0 parameter is passed then
+ the procedure will compute a value which will avoid overflow but
+ will cause underflow with 2046 variables or more.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SupersetHeavyBranch Cudd_SupersetShortPaths
+ Cudd_RemapOverApprox Cudd_BiasedUnderApprox Cudd_ReadSize]
+
+******************************************************************************/
+DdNode *
+Cudd_BiasedOverApprox(
+ DdManager *dd /* manager */,
+ DdNode *f /* function to be superset */,
+ DdNode *b /* bias function */,
+ int numVars /* number of variables in the support of f */,
+ int threshold /* when to stop approximation */,
+ double quality1 /* minimum improvement for accepted changes when b=1*/,
+ double quality0 /* minimum improvement for accepted changes when b=0 */)
+{
+ DdNode *subset, *g;
+
+ g = Cudd_Not(f);
+ do {
+ dd->reordered = 0;
+ subset = cuddBiasedUnderApprox(dd, g, b, numVars, threshold, quality1,
+ quality0);
+ } while (dd->reordered == 1);
+
+ return(Cudd_NotCond(subset, (subset != NULL)));
+
+} /* end of Cudd_BiasedOverApprox */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Applies Tom Shiple's underappoximation algorithm.]
+
+ Description [Applies Tom Shiple's underappoximation algorithm. Proceeds
+ in three phases:
+ <ul>
+ <li> collect information on each node in the BDD; this is done via DFS.
+ <li> traverse the BDD in top-down fashion and compute for each node
+ whether its elimination increases density.
+ <li> traverse the BDD via DFS and actually perform the elimination.
+ </ul>
+ Returns the approximated BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_UnderApprox]
+
+******************************************************************************/
+DdNode *
+cuddUnderApprox(
+ DdManager * dd /* DD manager */,
+ DdNode * f /* current DD */,
+ int numVars /* maximum number of variables */,
+ int threshold /* threshold under which approximation stops */,
+ int safe /* enforce safe approximation */,
+ double quality /* minimum improvement for accepted changes */)
+{
+ ApproxInfo *info;
+ DdNode *subset;
+ int result;
+
+ if (f == NULL) {
+ fprintf(dd->err, "Cannot subset, nil object\n");
+ return(NULL);
+ }
+
+ if (Cudd_IsConstant(f)) {
+ return(f);
+ }
+
+ /* Create table where node data are accessible via a hash table. */
+ info = gatherInfo(dd, f, numVars, safe);
+ if (info == NULL) {
+ (void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+
+ /* Mark nodes that should be replaced by zero. */
+ result = UAmarkNodes(dd, f, info, threshold, safe, quality);
+ if (result == 0) {
+ (void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
+ FREE(info->page);
+ st_free_table(info->table);
+ FREE(info);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+
+ /* Build the result. */
+ subset = UAbuildSubset(dd, f, info);
+#if 1
+ if (subset && info->size < Cudd_DagSize(subset))
+ (void) fprintf(dd->err, "Wrong prediction: %d versus actual %d\n",
+ info->size, Cudd_DagSize(subset));
+#endif
+ FREE(info->page);
+ st_free_table(info->table);
+ FREE(info);
+
+#ifdef DD_DEBUG
+ if (subset != NULL) {
+ cuddRef(subset);
+#if 0
+ (void) Cudd_DebugCheck(dd);
+ (void) Cudd_CheckKeys(dd);
+#endif
+ if (!Cudd_bddLeq(dd, subset, f)) {
+ (void) fprintf(dd->err, "Wrong subset\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ }
+ cuddDeref(subset);
+ }
+#endif
+ return(subset);
+
+} /* end of cuddUnderApprox */
+
+
+/**Function********************************************************************
+
+ Synopsis [Applies the remapping underappoximation algorithm.]
+
+ Description [Applies the remapping underappoximation algorithm.
+ Proceeds in three phases:
+ <ul>
+ <li> collect information on each node in the BDD; this is done via DFS.
+ <li> traverse the BDD in top-down fashion and compute for each node
+ whether remapping increases density.
+ <li> traverse the BDD via DFS and actually perform the elimination.
+ </ul>
+ Returns the approximated BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_RemapUnderApprox]
+
+******************************************************************************/
+DdNode *
+cuddRemapUnderApprox(
+ DdManager * dd /* DD manager */,
+ DdNode * f /* current DD */,
+ int numVars /* maximum number of variables */,
+ int threshold /* threshold under which approximation stops */,
+ double quality /* minimum improvement for accepted changes */)
+{
+ ApproxInfo *info;
+ DdNode *subset;
+ int result;
+
+ if (f == NULL) {
+ fprintf(dd->err, "Cannot subset, nil object\n");
+ dd->errorCode = CUDD_INVALID_ARG;
+ return(NULL);
+ }
+
+ if (Cudd_IsConstant(f)) {
+ return(f);
+ }
+
+ /* Create table where node data are accessible via a hash table. */
+ info = gatherInfo(dd, f, numVars, TRUE);
+ if (info == NULL) {
+ (void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+
+ /* Mark nodes that should be replaced by zero. */
+ result = RAmarkNodes(dd, f, info, threshold, quality);
+ if (result == 0) {
+ (void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
+ FREE(info->page);
+ st_free_table(info->table);
+ FREE(info);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+
+ /* Build the result. */
+ subset = RAbuildSubset(dd, f, info);
+#if 1
+ if (subset && info->size < Cudd_DagSize(subset))
+ (void) fprintf(dd->err, "Wrong prediction: %d versus actual %d\n",
+ info->size, Cudd_DagSize(subset));
+#endif
+ FREE(info->page);
+ st_free_table(info->table);
+ FREE(info);
+
+#ifdef DD_DEBUG
+ if (subset != NULL) {
+ cuddRef(subset);
+#if 0
+ (void) Cudd_DebugCheck(dd);
+ (void) Cudd_CheckKeys(dd);
+#endif
+ if (!Cudd_bddLeq(dd, subset, f)) {
+ (void) fprintf(dd->err, "Wrong subset\n");
+ }
+ cuddDeref(subset);
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ }
+#endif
+ return(subset);
+
+} /* end of cuddRemapUnderApprox */
+
+
+/**Function********************************************************************
+
+ Synopsis [Applies the biased remapping underappoximation algorithm.]
+
+ Description [Applies the biased remapping underappoximation algorithm.
+ Proceeds in three phases:
+ <ul>
+ <li> collect information on each node in the BDD; this is done via DFS.
+ <li> traverse the BDD in top-down fashion and compute for each node
+ whether remapping increases density.
+ <li> traverse the BDD via DFS and actually perform the elimination.
+ </ul>
+ Returns the approximated BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_BiasedUnderApprox]
+
+******************************************************************************/
+DdNode *
+cuddBiasedUnderApprox(
+ DdManager *dd /* DD manager */,
+ DdNode *f /* current DD */,
+ DdNode *b /* bias function */,
+ int numVars /* maximum number of variables */,
+ int threshold /* threshold under which approximation stops */,
+ double quality1 /* minimum improvement for accepted changes when b=1 */,
+ double quality0 /* minimum improvement for accepted changes when b=1 */)
+{
+ ApproxInfo *info;
+ DdNode *subset;
+ int result;
+ DdHashTable *cache;
+
+ if (f == NULL) {
+ fprintf(dd->err, "Cannot subset, nil object\n");
+ dd->errorCode = CUDD_INVALID_ARG;
+ return(NULL);
+ }
+
+ if (Cudd_IsConstant(f)) {
+ return(f);
+ }
+
+ /* Create table where node data are accessible via a hash table. */
+ info = gatherInfo(dd, f, numVars, TRUE);
+ if (info == NULL) {
+ (void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+
+ cache = cuddHashTableInit(dd,2,2);
+ result = BAapplyBias(dd, Cudd_Regular(f), b, info, cache);
+ if (result == CARE_ERROR) {
+ (void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
+ cuddHashTableQuit(cache);
+ FREE(info->page);
+ st_free_table(info->table);
+ FREE(info);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ cuddHashTableQuit(cache);
+
+ /* Mark nodes that should be replaced by zero. */
+ result = BAmarkNodes(dd, f, info, threshold, quality1, quality0);
+ if (result == 0) {
+ (void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
+ FREE(info->page);
+ st_free_table(info->table);
+ FREE(info);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+
+ /* Build the result. */
+ subset = RAbuildSubset(dd, f, info);
+#if 1
+ if (subset && info->size < Cudd_DagSize(subset))
+ (void) fprintf(dd->err, "Wrong prediction: %d versus actual %d\n",
+ info->size, Cudd_DagSize(subset));
+#endif
+ FREE(info->page);
+ st_free_table(info->table);
+ FREE(info);
+
+#ifdef DD_DEBUG
+ if (subset != NULL) {
+ cuddRef(subset);
+#if 0
+ (void) Cudd_DebugCheck(dd);
+ (void) Cudd_CheckKeys(dd);
+#endif
+ if (!Cudd_bddLeq(dd, subset, f)) {
+ (void) fprintf(dd->err, "Wrong subset\n");
+ }
+ cuddDeref(subset);
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ }
+#endif
+ return(subset);
+
+} /* end of cuddBiasedUnderApprox */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Recursively update the parity of the paths reaching a node.]
+
+ Description [Recursively update the parity of the paths reaching a node.
+ Assumes that node is regular and propagates the invariant.]
+
+ SideEffects [None]
+
+ SeeAlso [gatherInfoAux]
+
+******************************************************************************/
+static void
+updateParity(
+ DdNode * node /* function to analyze */,
+ ApproxInfo * info /* info on BDD */,
+ int newparity /* new parity for node */)
+{
+ NodeData *infoN;
+ DdNode *E;
+
+ if (!st_lookup(info->table, (char *)node, (char **)&infoN)) return;
+ if ((infoN->parity & newparity) != 0) return;
+ infoN->parity |= newparity;
+ if (Cudd_IsConstant(node)) return;
+ updateParity(cuddT(node),info,newparity);
+ E = cuddE(node);
+ if (Cudd_IsComplement(E)) {
+ updateParity(Cudd_Not(E),info,3-newparity);
+ } else {
+ updateParity(E,info,newparity);
+ }
+ return;
+
+} /* end of updateParity */
+
+
+/**Function********************************************************************
+
+ Synopsis [Recursively counts minterms and computes reference counts
+ of each node in the BDD.]
+
+ Description [Recursively counts minterms and computes reference
+ counts of each node in the BDD. Similar to the cuddCountMintermAux
+ which recursively counts the number of minterms for the dag rooted
+ at each node in terms of the total number of variables (max). It assumes
+ that the node pointer passed to it is regular and it maintains the
+ invariant.]
+
+ SideEffects [None]
+
+ SeeAlso [gatherInfo]
+
+******************************************************************************/
+static NodeData *
+gatherInfoAux(
+ DdNode * node /* function to analyze */,
+ ApproxInfo * info /* info on BDD */,
+ int parity /* gather parity information */)
+{
+ DdNode *N, *Nt, *Ne;
+ NodeData *infoN, *infoT, *infoE;
+
+ N = Cudd_Regular(node);
+
+ /* Check whether entry for this node exists. */
+ if (st_lookup(info->table, (char *)N, (char **)&infoN)) {
+ if (parity) {
+ /* Update parity and propagate. */
+ updateParity(N, info, 1 + (int) Cudd_IsComplement(node));
+ }
+ return(infoN);
+ }
+
+ /* Compute the cofactors. */
+ Nt = Cudd_NotCond(cuddT(N), N != node);
+ Ne = Cudd_NotCond(cuddE(N), N != node);
+
+ infoT = gatherInfoAux(Nt, info, parity);
+ if (infoT == NULL) return(NULL);
+ infoE = gatherInfoAux(Ne, info, parity);
+ if (infoE == NULL) return(NULL);
+
+ infoT->functionRef++;
+ infoE->functionRef++;
+
+ /* Point to the correct location in the page. */
+ infoN = &(info->page[info->index++]);
+ infoN->parity |= 1 + (short) Cudd_IsComplement(node);
+
+ infoN->mintermsP = infoT->mintermsP/2;
+ infoN->mintermsN = infoT->mintermsN/2;
+ if (Cudd_IsComplement(Ne) ^ Cudd_IsComplement(node)) {
+ infoN->mintermsP += infoE->mintermsN/2;
+ infoN->mintermsN += infoE->mintermsP/2;
+ } else {
+ infoN->mintermsP += infoE->mintermsP/2;
+ infoN->mintermsN += infoE->mintermsN/2;
+ }
+
+ /* Insert entry for the node in the table. */
+ if (st_insert(info->table,(char *)N, (char *)infoN) == ST_OUT_OF_MEM) {
+ return(NULL);
+ }
+ return(infoN);
+
+} /* end of gatherInfoAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Gathers information about each node.]
+
+ Description [Counts minterms and computes reference counts of each
+ node in the BDD . The minterm count is separately computed for the
+ node and its complement. This is to avoid cancellation
+ errors. Returns a pointer to the data structure holding the
+ information gathered if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddUnderApprox gatherInfoAux]
+
+******************************************************************************/
+static ApproxInfo *
+gatherInfo(
+ DdManager * dd /* manager */,
+ DdNode * node /* function to be analyzed */,
+ int numVars /* number of variables node depends on */,
+ int parity /* gather parity information */)
+{
+ ApproxInfo *info;
+ NodeData *infoTop;
+
+ /* If user did not give numVars value, set it to the maximum
+ ** exponent that the pow function can take. The -1 is due to the
+ ** discrepancy in the value that pow takes and the value that
+ ** log gives.
+ */
+ if (numVars == 0) {
+ numVars = DBL_MAX_EXP - 1;
+ }
+
+ info = ALLOC(ApproxInfo,1);
+ if (info == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ info->max = pow(2.0,(double) numVars);
+ info->one = DD_ONE(dd);
+ info->zero = Cudd_Not(info->one);
+ info->size = Cudd_DagSize(node);
+ /* All the information gathered will be stored in a contiguous
+ ** piece of memory, which is allocated here. This can be done
+ ** efficiently because we have counted the number of nodes of the
+ ** BDD. info->index points to the next available entry in the array
+ ** that stores the per-node information. */
+ info->page = ALLOC(NodeData,info->size);
+ if (info->page == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ FREE(info);
+ return(NULL);
+ }
+ memset(info->page, 0, info->size * sizeof(NodeData)); /* clear all page */
+ info->table = st_init_table(st_ptrcmp,st_ptrhash);
+ if (info->table == NULL) {
+ FREE(info->page);
+ FREE(info);
+ return(NULL);
+ }
+ /* We visit the DAG in post-order DFS. Hence, the constant node is
+ ** in first position, and the root of the DAG is in last position. */
+
+ /* Info for the constant node: Initialize only fields different from 0. */
+ if (st_insert(info->table, (char *)info->one, (char *)info->page) == ST_OUT_OF_MEM) {
+ FREE(info->page);
+ FREE(info);
+ st_free_table(info->table);
+ return(NULL);
+ }
+ info->page[0].mintermsP = info->max;
+ info->index = 1;
+
+ infoTop = gatherInfoAux(node,info,parity);
+ if (infoTop == NULL) {
+ FREE(info->page);
+ st_free_table(info->table);
+ FREE(info);
+ return(NULL);
+ }
+ if (Cudd_IsComplement(node)) {
+ info->minterms = infoTop->mintermsN;
+ } else {
+ info->minterms = infoTop->mintermsP;
+ }
+
+ infoTop->functionRef = 1;
+ return(info);
+
+} /* end of gatherInfo */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the nodes that would be eliminated if a given node
+ were replaced by zero.]
+
+ Description [Counts the nodes that would be eliminated if a given
+ node were replaced by zero. This procedure uses a queue passed by
+ the caller for efficiency: since the queue is left empty at the
+ endof the search, it can be reused as is by the next search. Returns
+ the count (always striclty positive) if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddUnderApprox]
+
+******************************************************************************/
+static int
+computeSavings(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * skip,
+ ApproxInfo * info,
+ DdLevelQueue * queue)
+{
+ NodeData *infoN;
+ LocalQueueItem *item;
+ DdNode *node;
+ int savings = 0;
+
+ node = Cudd_Regular(f);
+ skip = Cudd_Regular(skip);
+ /* Insert the given node in the level queue. Its local reference
+ ** count is set equal to the function reference count so that the
+ ** search will continue from it when it is retrieved. */
+ item = (LocalQueueItem *)
+ cuddLevelQueueEnqueue(queue,node,cuddI(dd,node->index));
+ if (item == NULL)
+ return(0);
+ (void) st_lookup(info->table, (char *)node, (char **)&infoN);
+ item->localRef = infoN->functionRef;
+
+ /* Process the queue. */
+ while (queue->first != NULL) {
+ item = (LocalQueueItem *) queue->first;
+ node = item->node;
+ cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
+ if (node == skip) continue;
+ (void) st_lookup(info->table, (char *)node, (char **)&infoN);
+ if (item->localRef != infoN->functionRef) {
+ /* This node is shared. */
+ continue;
+ }
+ savings++;
+ if (!cuddIsConstant(cuddT(node))) {
+ item = (LocalQueueItem *) cuddLevelQueueEnqueue(queue,cuddT(node),
+ cuddI(dd,cuddT(node)->index));
+ if (item == NULL) return(0);
+ item->localRef++;
+ }
+ if (!Cudd_IsConstant(cuddE(node))) {
+ item = (LocalQueueItem *) cuddLevelQueueEnqueue(queue,Cudd_Regular(cuddE(node)),
+ cuddI(dd,Cudd_Regular(cuddE(node))->index));
+ if (item == NULL) return(0);
+ item->localRef++;
+ }
+ }
+
+#ifdef DD_DEBUG
+ /* At the end of a local search the queue should be empty. */
+ assert(queue->size == 0);
+#endif
+ return(savings);
+
+} /* end of computeSavings */
+
+
+/**Function********************************************************************
+
+ Synopsis [Update function reference counts.]
+
+ Description [Update function reference counts to account for replacement.
+ Returns the number of nodes saved if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [UAmarkNodes RAmarkNodes]
+
+******************************************************************************/
+static int
+updateRefs(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * skip,
+ ApproxInfo * info,
+ DdLevelQueue * queue)
+{
+ NodeData *infoN;
+ LocalQueueItem *item;
+ DdNode *node;
+ int savings = 0;
+
+ node = Cudd_Regular(f);
+ /* Insert the given node in the level queue. Its function reference
+ ** count is set equal to 0 so that the search will continue from it
+ ** when it is retrieved. */
+ item = (LocalQueueItem *) cuddLevelQueueEnqueue(queue,node,cuddI(dd,node->index));
+ if (item == NULL)
+ return(0);
+ (void) st_lookup(info->table, (char *)node, (char **)&infoN);
+ infoN->functionRef = 0;
+
+ if (skip != NULL) {
+ /* Increase the function reference count of the node to be skipped
+ ** by 1 to account for the node pointing to it that will be created. */
+ skip = Cudd_Regular(skip);
+ (void) st_lookup(info->table, (char *)skip, (char **)&infoN);
+ infoN->functionRef++;
+ }
+
+ /* Process the queue. */
+ while (queue->first != NULL) {
+ item = (LocalQueueItem *) queue->first;
+ node = item->node;
+ cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
+ (void) st_lookup(info->table, (char *)node, (char **)&infoN);
+ if (infoN->functionRef != 0) {
+ /* This node is shared or must be skipped. */
+ continue;
+ }
+ savings++;
+ if (!cuddIsConstant(cuddT(node))) {
+ item = (LocalQueueItem *) cuddLevelQueueEnqueue(queue,cuddT(node),
+ cuddI(dd,cuddT(node)->index));
+ if (item == NULL) return(0);
+ (void) st_lookup(info->table, (char *)cuddT(node),
+ (char **)&infoN);
+ infoN->functionRef--;
+ }
+ if (!Cudd_IsConstant(cuddE(node))) {
+ item = (LocalQueueItem *) cuddLevelQueueEnqueue(queue,Cudd_Regular(cuddE(node)),
+ cuddI(dd,Cudd_Regular(cuddE(node))->index));
+ if (item == NULL) return(0);
+ (void) st_lookup(info->table, (char *)Cudd_Regular(cuddE(node)),
+ (char **)&infoN);
+ infoN->functionRef--;
+ }
+ }
+
+#ifdef DD_DEBUG
+ /* At the end of a local search the queue should be empty. */
+ assert(queue->size == 0);
+#endif
+ return(savings);
+
+} /* end of updateRefs */
+
+
+/**Function********************************************************************
+
+ Synopsis [Marks nodes for replacement by zero.]
+
+ Description [Marks nodes for replacement by zero. Returns 1 if successful;
+ 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddUnderApprox]
+
+******************************************************************************/
+static int
+UAmarkNodes(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be analyzed */,
+ ApproxInfo * info /* info on BDD */,
+ int threshold /* when to stop approximating */,
+ int safe /* enforce safe approximation */,
+ double quality /* minimum improvement for accepted changes */)
+{
+ DdLevelQueue *queue;
+ DdLevelQueue *localQueue;
+ NodeData *infoN;
+ GlobalQueueItem *item;
+ DdNode *node;
+ double numOnset;
+ double impactP, impactN;
+ int savings;
+
+#if 0
+ (void) printf("initial size = %d initial minterms = %g\n",
+ info->size, info->minterms);
+#endif
+ queue = cuddLevelQueueInit(dd->size,sizeof(GlobalQueueItem),info->size);
+ if (queue == NULL) {
+ return(0);
+ }
+ localQueue = cuddLevelQueueInit(dd->size,sizeof(LocalQueueItem),
+ dd->initSlots);
+ if (localQueue == NULL) {
+ cuddLevelQueueQuit(queue);
+ return(0);
+ }
+ node = Cudd_Regular(f);
+ item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,node,cuddI(dd,node->index));
+ if (item == NULL) {
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(0);
+ }
+ if (Cudd_IsComplement(f)) {
+ item->impactP = 0.0;
+ item->impactN = 1.0;
+ } else {
+ item->impactP = 1.0;
+ item->impactN = 0.0;
+ }
+ while (queue->first != NULL) {
+ /* If the size of the subset is below the threshold, quit. */
+ if (info->size <= threshold)
+ break;
+ item = (GlobalQueueItem *) queue->first;
+ node = item->node;
+ node = Cudd_Regular(node);
+ (void) st_lookup(info->table, (char *)node, (char **)&infoN);
+ if (safe && infoN->parity == 3) {
+ cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
+ continue;
+ }
+ impactP = item->impactP;
+ impactN = item->impactN;
+ numOnset = infoN->mintermsP * impactP + infoN->mintermsN * impactN;
+ savings = computeSavings(dd,node,NULL,info,localQueue);
+ if (savings == 0) {
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(0);
+ }
+ cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
+#if 0
+ (void) printf("node %p: impact = %g/%g numOnset = %g savings %d\n",
+ node, impactP, impactN, numOnset, savings);
+#endif
+ if ((1 - numOnset / info->minterms) >
+ quality * (1 - (double) savings / info->size)) {
+ infoN->replace = TRUE;
+ info->size -= savings;
+ info->minterms -=numOnset;
+#if 0
+ (void) printf("replace: new size = %d new minterms = %g\n",
+ info->size, info->minterms);
+#endif
+ savings -= updateRefs(dd,node,NULL,info,localQueue);
+ assert(savings == 0);
+ continue;
+ }
+ if (!cuddIsConstant(cuddT(node))) {
+ item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,cuddT(node),
+ cuddI(dd,cuddT(node)->index));
+ item->impactP += impactP/2.0;
+ item->impactN += impactN/2.0;
+ }
+ if (!Cudd_IsConstant(cuddE(node))) {
+ item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,Cudd_Regular(cuddE(node)),
+ cuddI(dd,Cudd_Regular(cuddE(node))->index));
+ if (Cudd_IsComplement(cuddE(node))) {
+ item->impactP += impactN/2.0;
+ item->impactN += impactP/2.0;
+ } else {
+ item->impactP += impactP/2.0;
+ item->impactN += impactN/2.0;
+ }
+ }
+ }
+
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(1);
+
+} /* end of UAmarkNodes */
+
+
+/**Function********************************************************************
+
+ Synopsis [Builds the subset BDD.]
+
+ Description [Builds the subset BDD. Based on the info table,
+ replaces selected nodes by zero. Returns a pointer to the result if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddUnderApprox]
+
+******************************************************************************/
+static DdNode *
+UAbuildSubset(
+ DdManager * dd /* DD manager */,
+ DdNode * node /* current node */,
+ ApproxInfo * info /* node info */)
+{
+
+ DdNode *Nt, *Ne, *N, *t, *e, *r;
+ NodeData *infoN;
+
+ if (Cudd_IsConstant(node))
+ return(node);
+
+ N = Cudd_Regular(node);
+
+ if (st_lookup(info->table, (char *)N, (char **)&infoN)) {
+ if (infoN->replace == TRUE) {
+ return(info->zero);
+ }
+ if (N == node ) {
+ if (infoN->resultP != NULL) {
+ return(infoN->resultP);
+ }
+ } else {
+ if (infoN->resultN != NULL) {
+ return(infoN->resultN);
+ }
+ }
+ } else {
+ (void) fprintf(dd->err,
+ "Something is wrong, ought to be in info table\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+
+ Nt = Cudd_NotCond(cuddT(N), Cudd_IsComplement(node));
+ Ne = Cudd_NotCond(cuddE(N), Cudd_IsComplement(node));
+
+ t = UAbuildSubset(dd, Nt, info);
+ if (t == NULL) {
+ return(NULL);
+ }
+ cuddRef(t);
+
+ e = UAbuildSubset(dd, Ne, info);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(dd,t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ if (Cudd_IsComplement(t)) {
+ t = Cudd_Not(t);
+ e = Cudd_Not(e);
+ r = (t == e) ? t : cuddUniqueInter(dd, N->index, t, e);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd, e);
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = (t == e) ? t : cuddUniqueInter(dd, N->index, t, e);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd, e);
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+
+ if (N == node) {
+ infoN->resultP = r;
+ } else {
+ infoN->resultN = r;
+ }
+
+ return(r);
+
+} /* end of UAbuildSubset */
+
+
+/**Function********************************************************************
+
+ Synopsis [Marks nodes for remapping.]
+
+ Description [Marks nodes for remapping. Returns 1 if successful; 0
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddRemapUnderApprox]
+
+******************************************************************************/
+static int
+RAmarkNodes(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be analyzed */,
+ ApproxInfo * info /* info on BDD */,
+ int threshold /* when to stop approximating */,
+ double quality /* minimum improvement for accepted changes */)
+{
+ DdLevelQueue *queue;
+ DdLevelQueue *localQueue;
+ NodeData *infoN, *infoT, *infoE;
+ GlobalQueueItem *item;
+ DdNode *node, *T, *E;
+ DdNode *shared; /* grandchild shared by the two children of node */
+ double numOnset;
+ double impact, impactP, impactN;
+ double minterms;
+ int savings;
+ int replace;
+
+#if 0
+ (void) fprintf(dd->out,"initial size = %d initial minterms = %g\n",
+ info->size, info->minterms);
+#endif
+ queue = cuddLevelQueueInit(dd->size,sizeof(GlobalQueueItem),info->size);
+ if (queue == NULL) {
+ return(0);
+ }
+ localQueue = cuddLevelQueueInit(dd->size,sizeof(LocalQueueItem),
+ dd->initSlots);
+ if (localQueue == NULL) {
+ cuddLevelQueueQuit(queue);
+ return(0);
+ }
+ /* Enqueue regular pointer to root and initialize impact. */
+ node = Cudd_Regular(f);
+ item = (GlobalQueueItem *)
+ cuddLevelQueueEnqueue(queue,node,cuddI(dd,node->index));
+ if (item == NULL) {
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(0);
+ }
+ if (Cudd_IsComplement(f)) {
+ item->impactP = 0.0;
+ item->impactN = 1.0;
+ } else {
+ item->impactP = 1.0;
+ item->impactN = 0.0;
+ }
+ /* The nodes retrieved here are guaranteed to be non-terminal.
+ ** The initial node is not terminal because constant nodes are
+ ** dealt with in the calling procedure. Subsequent nodes are inserted
+ ** only if they are not terminal. */
+ while (queue->first != NULL) {
+ /* If the size of the subset is below the threshold, quit. */
+ if (info->size <= threshold)
+ break;
+ item = (GlobalQueueItem *) queue->first;
+ node = item->node;
+#ifdef DD_DEBUG
+ assert(item->impactP >= 0 && item->impactP <= 1.0);
+ assert(item->impactN >= 0 && item->impactN <= 1.0);
+ assert(!Cudd_IsComplement(node));
+ assert(!Cudd_IsConstant(node));
+#endif
+ if (!st_lookup(info->table, (char *)node, (char **)&infoN)) {
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(0);
+ }
+#ifdef DD_DEBUG
+ assert(infoN->parity >= 1 && infoN->parity <= 3);
+#endif
+ if (infoN->parity == 3) {
+ /* This node can be reached through paths of different parity.
+ ** It is not safe to replace it, because remapping will give
+ ** an incorrect result, while replacement by 0 may cause node
+ ** splitting. */
+ cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
+ continue;
+ }
+ T = cuddT(node);
+ E = cuddE(node);
+ shared = NULL;
+ impactP = item->impactP;
+ impactN = item->impactN;
+ if (Cudd_bddLeq(dd,T,E)) {
+ /* Here we know that E is regular. */
+#ifdef DD_DEBUG
+ assert(!Cudd_IsComplement(E));
+#endif
+ (void) st_lookup(info->table, (char *)T, (char **)&infoT);
+ (void) st_lookup(info->table, (char *)E, (char **)&infoE);
+ if (infoN->parity == 1) {
+ impact = impactP;
+ minterms = infoE->mintermsP/2.0 - infoT->mintermsP/2.0;
+ if (infoE->functionRef == 1 && !Cudd_IsConstant(E)) {
+ savings = 1 + computeSavings(dd,E,NULL,info,localQueue);
+ if (savings == 1) {
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(0);
+ }
+ } else {
+ savings = 1;
+ }
+ replace = REPLACE_E;
+ } else {
+#ifdef DD_DEBUG
+ assert(infoN->parity == 2);
+#endif
+ impact = impactN;
+ minterms = infoT->mintermsN/2.0 - infoE->mintermsN/2.0;
+ if (infoT->functionRef == 1 && !Cudd_IsConstant(T)) {
+ savings = 1 + computeSavings(dd,T,NULL,info,localQueue);
+ if (savings == 1) {
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(0);
+ }
+ } else {
+ savings = 1;
+ }
+ replace = REPLACE_T;
+ }
+ numOnset = impact * minterms;
+ } else if (Cudd_bddLeq(dd,E,T)) {
+ /* Here E may be complemented. */
+ DdNode *Ereg = Cudd_Regular(E);
+ (void) st_lookup(info->table, (char *)T, (char **)&infoT);
+ (void) st_lookup(info->table, (char *)Ereg, (char **)&infoE);
+ if (infoN->parity == 1) {
+ impact = impactP;
+ minterms = infoT->mintermsP/2.0 -
+ ((E == Ereg) ? infoE->mintermsP : infoE->mintermsN)/2.0;
+ if (infoT->functionRef == 1 && !Cudd_IsConstant(T)) {
+ savings = 1 + computeSavings(dd,T,NULL,info,localQueue);
+ if (savings == 1) {
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(0);
+ }
+ } else {
+ savings = 1;
+ }
+ replace = REPLACE_T;
+ } else {
+#ifdef DD_DEBUG
+ assert(infoN->parity == 2);
+#endif
+ impact = impactN;
+ minterms = ((E == Ereg) ? infoE->mintermsN :
+ infoE->mintermsP)/2.0 - infoT->mintermsN/2.0;
+ if (infoE->functionRef == 1 && !Cudd_IsConstant(E)) {
+ savings = 1 + computeSavings(dd,E,NULL,info,localQueue);
+ if (savings == 1) {
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(0);
+ }
+ } else {
+ savings = 1;
+ }
+ replace = REPLACE_E;
+ }
+ numOnset = impact * minterms;
+ } else {
+ DdNode *Ereg = Cudd_Regular(E);
+ DdNode *TT = cuddT(T);
+ DdNode *ET = Cudd_NotCond(cuddT(Ereg), Cudd_IsComplement(E));
+ if (T->index == Ereg->index && TT == ET) {
+ shared = TT;
+ replace = REPLACE_TT;
+ } else {
+ DdNode *TE = cuddE(T);
+ DdNode *EE = Cudd_NotCond(cuddE(Ereg), Cudd_IsComplement(E));
+ if (T->index == Ereg->index && TE == EE) {
+ shared = TE;
+ replace = REPLACE_TE;
+ } else {
+ replace = REPLACE_N;
+ }
+ }
+ numOnset = infoN->mintermsP * impactP + infoN->mintermsN * impactN;
+ savings = computeSavings(dd,node,shared,info,localQueue);
+ if (shared != NULL) {
+ NodeData *infoS;
+ (void) st_lookup(info->table, (char *)Cudd_Regular(shared),
+ (char **)&infoS);
+ if (Cudd_IsComplement(shared)) {
+ numOnset -= (infoS->mintermsN * impactP +
+ infoS->mintermsP * impactN)/2.0;
+ } else {
+ numOnset -= (infoS->mintermsP * impactP +
+ infoS->mintermsN * impactN)/2.0;
+ }
+ savings--;
+ }
+ }
+
+ cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
+#if 0
+ if (replace == REPLACE_T || replace == REPLACE_E)
+ (void) printf("node %p: impact = %g numOnset = %g savings %d\n",
+ node, impact, numOnset, savings);
+ else
+ (void) printf("node %p: impact = %g/%g numOnset = %g savings %d\n",
+ node, impactP, impactN, numOnset, savings);
+#endif
+ if ((1 - numOnset / info->minterms) >
+ quality * (1 - (double) savings / info->size)) {
+ infoN->replace = replace;
+ info->size -= savings;
+ info->minterms -=numOnset;
+#if 0
+ (void) printf("remap(%d): new size = %d new minterms = %g\n",
+ replace, info->size, info->minterms);
+#endif
+ if (replace == REPLACE_N) {
+ savings -= updateRefs(dd,node,NULL,info,localQueue);
+ } else if (replace == REPLACE_T) {
+ savings -= updateRefs(dd,node,E,info,localQueue);
+ } else if (replace == REPLACE_E) {
+ savings -= updateRefs(dd,node,T,info,localQueue);
+ } else {
+#ifdef DD_DEBUG
+ assert(replace == REPLACE_TT || replace == REPLACE_TE);
+#endif
+ savings -= updateRefs(dd,node,shared,info,localQueue) - 1;
+ }
+ assert(savings == 0);
+ } else {
+ replace = NOTHING;
+ }
+ if (replace == REPLACE_N) continue;
+ if ((replace == REPLACE_E || replace == NOTHING) &&
+ !cuddIsConstant(cuddT(node))) {
+ item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,cuddT(node),
+ cuddI(dd,cuddT(node)->index));
+ if (replace == REPLACE_E) {
+ item->impactP += impactP;
+ item->impactN += impactN;
+ } else {
+ item->impactP += impactP/2.0;
+ item->impactN += impactN/2.0;
+ }
+ }
+ if ((replace == REPLACE_T || replace == NOTHING) &&
+ !Cudd_IsConstant(cuddE(node))) {
+ item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,Cudd_Regular(cuddE(node)),
+ cuddI(dd,Cudd_Regular(cuddE(node))->index));
+ if (Cudd_IsComplement(cuddE(node))) {
+ if (replace == REPLACE_T) {
+ item->impactP += impactN;
+ item->impactN += impactP;
+ } else {
+ item->impactP += impactN/2.0;
+ item->impactN += impactP/2.0;
+ }
+ } else {
+ if (replace == REPLACE_T) {
+ item->impactP += impactP;
+ item->impactN += impactN;
+ } else {
+ item->impactP += impactP/2.0;
+ item->impactN += impactN/2.0;
+ }
+ }
+ }
+ if ((replace == REPLACE_TT || replace == REPLACE_TE) &&
+ !Cudd_IsConstant(shared)) {
+ item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,Cudd_Regular(shared),
+ cuddI(dd,Cudd_Regular(shared)->index));
+ if (Cudd_IsComplement(shared)) {
+ if (replace == REPLACE_T) {
+ item->impactP += impactN;
+ item->impactN += impactP;
+ } else {
+ item->impactP += impactN/2.0;
+ item->impactN += impactP/2.0;
+ }
+ } else {
+ if (replace == REPLACE_T) {
+ item->impactP += impactP;
+ item->impactN += impactN;
+ } else {
+ item->impactP += impactP/2.0;
+ item->impactN += impactN/2.0;
+ }
+ }
+ }
+ }
+
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(1);
+
+} /* end of RAmarkNodes */
+
+
+/**Function********************************************************************
+
+ Synopsis [Marks nodes for remapping.]
+
+ Description [Marks nodes for remapping. Returns 1 if successful; 0
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddRemapUnderApprox]
+
+******************************************************************************/
+static int
+BAmarkNodes(
+ DdManager *dd /* manager */,
+ DdNode *f /* function to be analyzed */,
+ ApproxInfo *info /* info on BDD */,
+ int threshold /* when to stop approximating */,
+ double quality1 /* minimum improvement for accepted changes when b=1 */,
+ double quality0 /* minimum improvement for accepted changes when b=0 */)
+{
+ DdLevelQueue *queue;
+ DdLevelQueue *localQueue;
+ NodeData *infoN, *infoT, *infoE;
+ GlobalQueueItem *item;
+ DdNode *node, *T, *E;
+ DdNode *shared; /* grandchild shared by the two children of node */
+ double numOnset;
+ double impact, impactP, impactN;
+ double minterms;
+ double quality;
+ int savings;
+ int replace;
+
+#if 0
+ (void) fprintf(dd->out,"initial size = %d initial minterms = %g\n",
+ info->size, info->minterms);
+#endif
+ queue = cuddLevelQueueInit(dd->size,sizeof(GlobalQueueItem),info->size);
+ if (queue == NULL) {
+ return(0);
+ }
+ localQueue = cuddLevelQueueInit(dd->size,sizeof(LocalQueueItem),
+ dd->initSlots);
+ if (localQueue == NULL) {
+ cuddLevelQueueQuit(queue);
+ return(0);
+ }
+ /* Enqueue regular pointer to root and initialize impact. */
+ node = Cudd_Regular(f);
+ item = (GlobalQueueItem *)
+ cuddLevelQueueEnqueue(queue,node,cuddI(dd,node->index));
+ if (item == NULL) {
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(0);
+ }
+ if (Cudd_IsComplement(f)) {
+ item->impactP = 0.0;
+ item->impactN = 1.0;
+ } else {
+ item->impactP = 1.0;
+ item->impactN = 0.0;
+ }
+ /* The nodes retrieved here are guaranteed to be non-terminal.
+ ** The initial node is not terminal because constant nodes are
+ ** dealt with in the calling procedure. Subsequent nodes are inserted
+ ** only if they are not terminal. */
+ while (queue->first != NULL) {
+ /* If the size of the subset is below the threshold, quit. */
+ if (info->size <= threshold)
+ break;
+ item = (GlobalQueueItem *) queue->first;
+ node = item->node;
+#ifdef DD_DEBUG
+ assert(item->impactP >= 0 && item->impactP <= 1.0);
+ assert(item->impactN >= 0 && item->impactN <= 1.0);
+ assert(!Cudd_IsComplement(node));
+ assert(!Cudd_IsConstant(node));
+#endif
+ if (!st_lookup(info->table, (char *)node, (char **)&infoN)) {
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(0);
+ }
+ quality = infoN->care ? quality1 : quality0;
+#ifdef DD_DEBUG
+ assert(infoN->parity >= 1 && infoN->parity <= 3);
+#endif
+ if (infoN->parity == 3) {
+ /* This node can be reached through paths of different parity.
+ ** It is not safe to replace it, because remapping will give
+ ** an incorrect result, while replacement by 0 may cause node
+ ** splitting. */
+ cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
+ continue;
+ }
+ T = cuddT(node);
+ E = cuddE(node);
+ shared = NULL;
+ impactP = item->impactP;
+ impactN = item->impactN;
+ if (Cudd_bddLeq(dd,T,E)) {
+ /* Here we know that E is regular. */
+#ifdef DD_DEBUG
+ assert(!Cudd_IsComplement(E));
+#endif
+ (void) st_lookup(info->table, (char *)T, (char **)&infoT);
+ (void) st_lookup(info->table, (char *)E, (char **)&infoE);
+ if (infoN->parity == 1) {
+ impact = impactP;
+ minterms = infoE->mintermsP/2.0 - infoT->mintermsP/2.0;
+ if (infoE->functionRef == 1 && !Cudd_IsConstant(E)) {
+ savings = 1 + computeSavings(dd,E,NULL,info,localQueue);
+ if (savings == 1) {
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(0);
+ }
+ } else {
+ savings = 1;
+ }
+ replace = REPLACE_E;
+ } else {
+#ifdef DD_DEBUG
+ assert(infoN->parity == 2);
+#endif
+ impact = impactN;
+ minterms = infoT->mintermsN/2.0 - infoE->mintermsN/2.0;
+ if (infoT->functionRef == 1 && !Cudd_IsConstant(T)) {
+ savings = 1 + computeSavings(dd,T,NULL,info,localQueue);
+ if (savings == 1) {
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(0);
+ }
+ } else {
+ savings = 1;
+ }
+ replace = REPLACE_T;
+ }
+ numOnset = impact * minterms;
+ } else if (Cudd_bddLeq(dd,E,T)) {
+ /* Here E may be complemented. */
+ DdNode *Ereg = Cudd_Regular(E);
+ (void) st_lookup(info->table, (char *)T, (char **)&infoT);
+ (void) st_lookup(info->table, (char *)Ereg, (char **)&infoE);
+ if (infoN->parity == 1) {
+ impact = impactP;
+ minterms = infoT->mintermsP/2.0 -
+ ((E == Ereg) ? infoE->mintermsP : infoE->mintermsN)/2.0;
+ if (infoT->functionRef == 1 && !Cudd_IsConstant(T)) {
+ savings = 1 + computeSavings(dd,T,NULL,info,localQueue);
+ if (savings == 1) {
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(0);
+ }
+ } else {
+ savings = 1;
+ }
+ replace = REPLACE_T;
+ } else {
+#ifdef DD_DEBUG
+ assert(infoN->parity == 2);
+#endif
+ impact = impactN;
+ minterms = ((E == Ereg) ? infoE->mintermsN :
+ infoE->mintermsP)/2.0 - infoT->mintermsN/2.0;
+ if (infoE->functionRef == 1 && !Cudd_IsConstant(E)) {
+ savings = 1 + computeSavings(dd,E,NULL,info,localQueue);
+ if (savings == 1) {
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(0);
+ }
+ } else {
+ savings = 1;
+ }
+ replace = REPLACE_E;
+ }
+ numOnset = impact * minterms;
+ } else {
+ DdNode *Ereg = Cudd_Regular(E);
+ DdNode *TT = cuddT(T);
+ DdNode *ET = Cudd_NotCond(cuddT(Ereg), Cudd_IsComplement(E));
+ if (T->index == Ereg->index && TT == ET) {
+ shared = TT;
+ replace = REPLACE_TT;
+ } else {
+ DdNode *TE = cuddE(T);
+ DdNode *EE = Cudd_NotCond(cuddE(Ereg), Cudd_IsComplement(E));
+ if (T->index == Ereg->index && TE == EE) {
+ shared = TE;
+ replace = REPLACE_TE;
+ } else {
+ replace = REPLACE_N;
+ }
+ }
+ numOnset = infoN->mintermsP * impactP + infoN->mintermsN * impactN;
+ savings = computeSavings(dd,node,shared,info,localQueue);
+ if (shared != NULL) {
+ NodeData *infoS;
+ (void) st_lookup(info->table, (char *)Cudd_Regular(shared),
+ (char **)&infoS);
+ if (Cudd_IsComplement(shared)) {
+ numOnset -= (infoS->mintermsN * impactP +
+ infoS->mintermsP * impactN)/2.0;
+ } else {
+ numOnset -= (infoS->mintermsP * impactP +
+ infoS->mintermsN * impactN)/2.0;
+ }
+ savings--;
+ }
+ }
+
+ cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
+#if 0
+ if (replace == REPLACE_T || replace == REPLACE_E)
+ (void) printf("node %p: impact = %g numOnset = %g savings %d\n",
+ node, impact, numOnset, savings);
+ else
+ (void) printf("node %p: impact = %g/%g numOnset = %g savings %d\n",
+ node, impactP, impactN, numOnset, savings);
+#endif
+ if ((1 - numOnset / info->minterms) >
+ quality * (1 - (double) savings / info->size)) {
+ infoN->replace = replace;
+ info->size -= savings;
+ info->minterms -=numOnset;
+#if 0
+ (void) printf("remap(%d): new size = %d new minterms = %g\n",
+ replace, info->size, info->minterms);
+#endif
+ if (replace == REPLACE_N) {
+ savings -= updateRefs(dd,node,NULL,info,localQueue);
+ } else if (replace == REPLACE_T) {
+ savings -= updateRefs(dd,node,E,info,localQueue);
+ } else if (replace == REPLACE_E) {
+ savings -= updateRefs(dd,node,T,info,localQueue);
+ } else {
+#ifdef DD_DEBUG
+ assert(replace == REPLACE_TT || replace == REPLACE_TE);
+#endif
+ savings -= updateRefs(dd,node,shared,info,localQueue) - 1;
+ }
+ assert(savings == 0);
+ } else {
+ replace = NOTHING;
+ }
+ if (replace == REPLACE_N) continue;
+ if ((replace == REPLACE_E || replace == NOTHING) &&
+ !cuddIsConstant(cuddT(node))) {
+ item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,cuddT(node),
+ cuddI(dd,cuddT(node)->index));
+ if (replace == REPLACE_E) {
+ item->impactP += impactP;
+ item->impactN += impactN;
+ } else {
+ item->impactP += impactP/2.0;
+ item->impactN += impactN/2.0;
+ }
+ }
+ if ((replace == REPLACE_T || replace == NOTHING) &&
+ !Cudd_IsConstant(cuddE(node))) {
+ item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,Cudd_Regular(cuddE(node)),
+ cuddI(dd,Cudd_Regular(cuddE(node))->index));
+ if (Cudd_IsComplement(cuddE(node))) {
+ if (replace == REPLACE_T) {
+ item->impactP += impactN;
+ item->impactN += impactP;
+ } else {
+ item->impactP += impactN/2.0;
+ item->impactN += impactP/2.0;
+ }
+ } else {
+ if (replace == REPLACE_T) {
+ item->impactP += impactP;
+ item->impactN += impactN;
+ } else {
+ item->impactP += impactP/2.0;
+ item->impactN += impactN/2.0;
+ }
+ }
+ }
+ if ((replace == REPLACE_TT || replace == REPLACE_TE) &&
+ !Cudd_IsConstant(shared)) {
+ item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,Cudd_Regular(shared),
+ cuddI(dd,Cudd_Regular(shared)->index));
+ if (Cudd_IsComplement(shared)) {
+ if (replace == REPLACE_T) {
+ item->impactP += impactN;
+ item->impactN += impactP;
+ } else {
+ item->impactP += impactN/2.0;
+ item->impactN += impactP/2.0;
+ }
+ } else {
+ if (replace == REPLACE_T) {
+ item->impactP += impactP;
+ item->impactN += impactN;
+ } else {
+ item->impactP += impactP/2.0;
+ item->impactN += impactN/2.0;
+ }
+ }
+ }
+ }
+
+ cuddLevelQueueQuit(queue);
+ cuddLevelQueueQuit(localQueue);
+ return(1);
+
+} /* end of BAmarkNodes */
+
+
+/**Function********************************************************************
+
+ Synopsis [Builds the subset BDD for cuddRemapUnderApprox.]
+
+ Description [Builds the subset BDDfor cuddRemapUnderApprox. Based
+ on the info table, performs remapping or replacement at selected
+ nodes. Returns a pointer to the result if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddRemapUnderApprox]
+
+******************************************************************************/
+static DdNode *
+RAbuildSubset(
+ DdManager * dd /* DD manager */,
+ DdNode * node /* current node */,
+ ApproxInfo * info /* node info */)
+{
+ DdNode *Nt, *Ne, *N, *t, *e, *r;
+ NodeData *infoN;
+
+ if (Cudd_IsConstant(node))
+ return(node);
+
+ N = Cudd_Regular(node);
+
+ Nt = Cudd_NotCond(cuddT(N), Cudd_IsComplement(node));
+ Ne = Cudd_NotCond(cuddE(N), Cudd_IsComplement(node));
+
+ if (st_lookup(info->table, (char *)N, (char **)&infoN)) {
+ if (N == node ) {
+ if (infoN->resultP != NULL) {
+ return(infoN->resultP);
+ }
+ } else {
+ if (infoN->resultN != NULL) {
+ return(infoN->resultN);
+ }
+ }
+ if (infoN->replace == REPLACE_T) {
+ r = RAbuildSubset(dd, Ne, info);
+ return(r);
+ } else if (infoN->replace == REPLACE_E) {
+ r = RAbuildSubset(dd, Nt, info);
+ return(r);
+ } else if (infoN->replace == REPLACE_N) {
+ return(info->zero);
+ } else if (infoN->replace == REPLACE_TT) {
+ DdNode *Ntt = Cudd_NotCond(cuddT(cuddT(N)),
+ Cudd_IsComplement(node));
+ int index = cuddT(N)->index;
+ DdNode *e = info->zero;
+ DdNode *t = RAbuildSubset(dd, Ntt, info);
+ if (t == NULL) {
+ return(NULL);
+ }
+ cuddRef(t);
+ if (Cudd_IsComplement(t)) {
+ t = Cudd_Not(t);
+ e = Cudd_Not(e);
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ }
+ cuddDeref(t);
+ return(r);
+ } else if (infoN->replace == REPLACE_TE) {
+ DdNode *Nte = Cudd_NotCond(cuddE(cuddT(N)),
+ Cudd_IsComplement(node));
+ int index = cuddT(N)->index;
+ DdNode *t = info->one;
+ DdNode *e = RAbuildSubset(dd, Nte, info);
+ if (e == NULL) {
+ return(NULL);
+ }
+ cuddRef(e);
+ e = Cudd_Not(e);
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd, e);
+ return(NULL);
+ }
+ r =Cudd_Not(r);
+ cuddDeref(e);
+ return(r);
+ }
+ } else {
+ (void) fprintf(dd->err,
+ "Something is wrong, ought to be in info table\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+
+ t = RAbuildSubset(dd, Nt, info);
+ if (t == NULL) {
+ return(NULL);
+ }
+ cuddRef(t);
+
+ e = RAbuildSubset(dd, Ne, info);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(dd,t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ if (Cudd_IsComplement(t)) {
+ t = Cudd_Not(t);
+ e = Cudd_Not(e);
+ r = (t == e) ? t : cuddUniqueInter(dd, N->index, t, e);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd, e);
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = (t == e) ? t : cuddUniqueInter(dd, N->index, t, e);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd, e);
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+
+ if (N == node) {
+ infoN->resultP = r;
+ } else {
+ infoN->resultN = r;
+ }
+
+ return(r);
+
+} /* end of RAbuildSubset */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds don't care nodes.]
+
+ Description [Finds don't care nodes by traversing f and b in parallel.
+ Returns the care status of the visited f node if successful; CARE_ERROR
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddBiasedUnderApprox]
+
+******************************************************************************/
+static int
+BAapplyBias(
+ DdManager *dd,
+ DdNode *f,
+ DdNode *b,
+ ApproxInfo *info,
+ DdHashTable *cache)
+{
+ DdNode *one, *zero, *res;
+ DdNode *Ft, *Fe, *B, *Bt, *Be;
+ unsigned int topf, topb;
+ NodeData *infoF;
+ int careT, careE;
+
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+
+ if (!st_lookup(info->table, (char *) f, (char **)&infoF))
+ return(CARE_ERROR);
+ if (f == one) return(TOTAL_CARE);
+ if (b == zero) return(infoF->care);
+ if (infoF->care == TOTAL_CARE) return(TOTAL_CARE);
+
+ if ((f->ref != 1 || Cudd_Regular(b)->ref != 1) &&
+ (res = cuddHashTableLookup2(cache,f,b)) != NULL) {
+ if (res->ref == 0) {
+ cache->manager->dead++;
+ cache->manager->constants.dead++;
+ }
+ return(infoF->care);
+ }
+
+ topf = dd->perm[f->index];
+ B = Cudd_Regular(b);
+ topb = cuddI(dd,B->index);
+ if (topf <= topb) {
+ Ft = cuddT(f); Fe = cuddE(f);
+ } else {
+ Ft = Fe = f;
+ }
+ if (topb <= topf) {
+ /* We know that b is not constant because f is not. */
+ Bt = cuddT(B); Be = cuddE(B);
+ if (Cudd_IsComplement(b)) {
+ Bt = Cudd_Not(Bt);
+ Be = Cudd_Not(Be);
+ }
+ } else {
+ Bt = Be = b;
+ }
+
+ careT = BAapplyBias(dd, Ft, Bt, info, cache);
+ if (careT == CARE_ERROR)
+ return(CARE_ERROR);
+ careE = BAapplyBias(dd, Cudd_Regular(Fe), Be, info, cache);
+ if (careE == CARE_ERROR)
+ return(CARE_ERROR);
+ if (careT == TOTAL_CARE && careE == TOTAL_CARE) {
+ infoF->care = TOTAL_CARE;
+ } else {
+ infoF->care = CARE;
+ }
+
+ if (f->ref != 1 || Cudd_Regular(b)->ref != 1) {
+ ptrint fanout = (ptrint) f->ref * Cudd_Regular(b)->ref;
+ cuddSatDec(fanout);
+ if (!cuddHashTableInsert2(cache,f,b,one,fanout)) {
+ return(CARE_ERROR);
+ }
+ }
+ return(infoF->care);
+
+} /* end of BAapplyBias */
diff --git a/src/bdd/cudd/cuddBddAbs.c b/src/bdd/cudd/cuddBddAbs.c
new file mode 100644
index 00000000..20a8f15a
--- /dev/null
+++ b/src/bdd/cudd/cuddBddAbs.c
@@ -0,0 +1,689 @@
+/**CFile***********************************************************************
+
+ FileName [cuddBddAbs.c]
+
+ PackageName [cudd]
+
+ Synopsis [Quantification functions for BDDs.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_bddExistAbstract()
+ <li> Cudd_bddXorExistAbstract()
+ <li> Cudd_bddUnivAbstract()
+ <li> Cudd_bddBooleanDiff()
+ <li> Cudd_bddVarIsDependent()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddBddExistAbstractRecur()
+ <li> cuddBddXorExistAbstractRecur()
+ <li> cuddBddBooleanDiffRecur()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> bddCheckPositiveCube()
+ </ul>
+ ]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddBddAbs.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int bddCheckPositiveCube ARGS((DdManager *manager, DdNode *cube));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Existentially abstracts all the variables in cube from f.]
+
+ Description [Existentially abstracts all the variables in cube from f.
+ Returns the abstracted BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddUnivAbstract Cudd_addExistAbstract]
+
+******************************************************************************/
+DdNode *
+Cudd_bddExistAbstract(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * cube)
+{
+ DdNode *res;
+
+ if (bddCheckPositiveCube(manager, cube) == 0) {
+ (void) fprintf(manager->err,
+ "Error: Can only abstract positive cubes\n");
+ manager->errorCode = CUDD_INVALID_ARG;
+ return(NULL);
+ }
+
+ do {
+ manager->reordered = 0;
+ res = cuddBddExistAbstractRecur(manager, f, cube);
+ } while (manager->reordered == 1);
+
+ return(res);
+
+} /* end of Cudd_bddExistAbstract */
+
+
+/**Function********************************************************************
+
+ Synopsis [Takes the exclusive OR of two BDDs and simultaneously abstracts the
+ variables in cube.]
+
+ Description [Takes the exclusive OR of two BDDs and simultaneously abstracts
+ the variables in cube. The variables are existentially abstracted. Returns a
+ pointer to the result is successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddUnivAbstract Cudd_bddExistAbstract Cudd_bddAndAbstract]
+
+******************************************************************************/
+DdNode *
+Cudd_bddXorExistAbstract(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * g,
+ DdNode * cube)
+{
+ DdNode *res;
+
+ if (bddCheckPositiveCube(manager, cube) == 0) {
+ (void) fprintf(manager->err,
+ "Error: Can only abstract positive cubes\n");
+ manager->errorCode = CUDD_INVALID_ARG;
+ return(NULL);
+ }
+
+ do {
+ manager->reordered = 0;
+ res = cuddBddXorExistAbstractRecur(manager, f, g, cube);
+ } while (manager->reordered == 1);
+
+ return(res);
+
+} /* end of Cudd_bddXorExistAbstract */
+
+
+/**Function********************************************************************
+
+ Synopsis [Universally abstracts all the variables in cube from f.]
+
+ Description [Universally abstracts all the variables in cube from f.
+ Returns the abstracted BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddExistAbstract Cudd_addUnivAbstract]
+
+******************************************************************************/
+DdNode *
+Cudd_bddUnivAbstract(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * cube)
+{
+ DdNode *res;
+
+ if (bddCheckPositiveCube(manager, cube) == 0) {
+ (void) fprintf(manager->err,
+ "Error: Can only abstract positive cubes\n");
+ manager->errorCode = CUDD_INVALID_ARG;
+ return(NULL);
+ }
+
+ do {
+ manager->reordered = 0;
+ res = cuddBddExistAbstractRecur(manager, Cudd_Not(f), cube);
+ } while (manager->reordered == 1);
+ if (res != NULL) res = Cudd_Not(res);
+
+ return(res);
+
+} /* end of Cudd_bddUnivAbstract */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the boolean difference of f with respect to x.]
+
+ Description [Computes the boolean difference of f with respect to the
+ variable with index x. Returns the BDD of the boolean difference if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_bddBooleanDiff(
+ DdManager * manager,
+ DdNode * f,
+ int x)
+{
+ DdNode *res, *var;
+
+ /* If the variable is not currently in the manager, f cannot
+ ** depend on it.
+ */
+ if (x >= manager->size) return(Cudd_Not(DD_ONE(manager)));
+ var = manager->vars[x];
+
+ do {
+ manager->reordered = 0;
+ res = cuddBddBooleanDiffRecur(manager, Cudd_Regular(f), var);
+ } while (manager->reordered == 1);
+
+ return(res);
+
+} /* end of Cudd_bddBooleanDiff */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether a variable is dependent on others in a
+ function.]
+
+ Description [Checks whether a variable is dependent on others in a
+ function. Returns 1 if the variable is dependent; 0 otherwise. No
+ new nodes are created.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+Cudd_bddVarIsDependent(
+ DdManager *dd, /* manager */
+ DdNode *f, /* function */
+ DdNode *var /* variable */)
+{
+ DdNode *F, *res, *zero, *ft, *fe;
+ unsigned topf, level;
+ DdNode *(*cacheOp)(DdManager *, DdNode *, DdNode *);
+ int retval;
+
+ zero = Cudd_Not(DD_ONE(dd));
+ if (Cudd_IsConstant(f)) return(f == zero);
+
+ /* From now on f is not constant. */
+ F = Cudd_Regular(f);
+ topf = (unsigned) dd->perm[F->index];
+ level = (unsigned) dd->perm[var->index];
+
+ /* Check terminal case. If topf > index of var, f does not depend on var.
+ ** Therefore, var is not dependent in f. */
+ if (topf > level) {
+ return(0);
+ }
+
+ cacheOp =
+ (DdNode *(*)(DdManager *, DdNode *, DdNode *)) Cudd_bddVarIsDependent;
+ res = cuddCacheLookup2(dd,cacheOp,f,var);
+ if (res != NULL) {
+ return(res != zero);
+ }
+
+ /* Compute cofactors. */
+ ft = Cudd_NotCond(cuddT(F), f != F);
+ fe = Cudd_NotCond(cuddE(F), f != F);
+
+ if (topf == level) {
+ retval = Cudd_bddLeq(dd,ft,Cudd_Not(fe));
+ } else {
+ retval = Cudd_bddVarIsDependent(dd,ft,var) &&
+ Cudd_bddVarIsDependent(dd,fe,var);
+ }
+
+ cuddCacheInsert2(dd,cacheOp,f,var,Cudd_NotCond(zero,retval));
+
+ return(retval);
+
+} /* Cudd_bddVarIsDependent */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive steps of Cudd_bddExistAbstract.]
+
+ Description [Performs the recursive steps of Cudd_bddExistAbstract.
+ Returns the BDD obtained by abstracting the variables
+ of cube from f if successful; NULL otherwise. It is also used by
+ Cudd_bddUnivAbstract.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddExistAbstract Cudd_bddUnivAbstract]
+
+******************************************************************************/
+DdNode *
+cuddBddExistAbstractRecur(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * cube)
+{
+ DdNode *F, *T, *E, *res, *res1, *res2, *one;
+
+ statLine(manager);
+ one = DD_ONE(manager);
+ F = Cudd_Regular(f);
+
+ /* Cube is guaranteed to be a cube at this point. */
+ if (cube == one || F == one) {
+ return(f);
+ }
+ /* From now on, f and cube are non-constant. */
+
+ /* Abstract a variable that does not appear in f. */
+ while (manager->perm[F->index] > manager->perm[cube->index]) {
+ cube = cuddT(cube);
+ if (cube == one) return(f);
+ }
+
+ /* Check the cache. */
+ if (F->ref != 1 && (res = cuddCacheLookup2(manager, Cudd_bddExistAbstract, f, cube)) != NULL) {
+ return(res);
+ }
+
+ /* Compute the cofactors of f. */
+ T = cuddT(F); E = cuddE(F);
+ if (f != F) {
+ T = Cudd_Not(T); E = Cudd_Not(E);
+ }
+
+ /* If the two indices are the same, so are their levels. */
+ if (F->index == cube->index) {
+ if (T == one || E == one || T == Cudd_Not(E)) {
+ return(one);
+ }
+ res1 = cuddBddExistAbstractRecur(manager, T, cuddT(cube));
+ if (res1 == NULL) return(NULL);
+ if (res1 == one) {
+ if (F->ref != 1)
+ cuddCacheInsert2(manager, Cudd_bddExistAbstract, f, cube, one);
+ return(one);
+ }
+ cuddRef(res1);
+ res2 = cuddBddExistAbstractRecur(manager, E, cuddT(cube));
+ if (res2 == NULL) {
+ Cudd_IterDerefBdd(manager,res1);
+ return(NULL);
+ }
+ cuddRef(res2);
+ res = cuddBddAndRecur(manager, Cudd_Not(res1), Cudd_Not(res2));
+ if (res == NULL) {
+ Cudd_IterDerefBdd(manager, res1);
+ Cudd_IterDerefBdd(manager, res2);
+ return(NULL);
+ }
+ res = Cudd_Not(res);
+ cuddRef(res);
+ Cudd_IterDerefBdd(manager, res1);
+ Cudd_IterDerefBdd(manager, res2);
+ if (F->ref != 1)
+ cuddCacheInsert2(manager, Cudd_bddExistAbstract, f, cube, res);
+ cuddDeref(res);
+ return(res);
+ } else { /* if (cuddI(manager,F->index) < cuddI(manager,cube->index)) */
+ res1 = cuddBddExistAbstractRecur(manager, T, cube);
+ if (res1 == NULL) return(NULL);
+ cuddRef(res1);
+ res2 = cuddBddExistAbstractRecur(manager, E, cube);
+ if (res2 == NULL) {
+ Cudd_IterDerefBdd(manager, res1);
+ return(NULL);
+ }
+ cuddRef(res2);
+ /* ITE takes care of possible complementation of res1 and of the
+ ** case in which res1 == res2. */
+ res = cuddBddIteRecur(manager, manager->vars[F->index], res1, res2);
+ if (res == NULL) {
+ Cudd_IterDerefBdd(manager, res1);
+ Cudd_IterDerefBdd(manager, res2);
+ return(NULL);
+ }
+ cuddDeref(res1);
+ cuddDeref(res2);
+ if (F->ref != 1)
+ cuddCacheInsert2(manager, Cudd_bddExistAbstract, f, cube, res);
+ return(res);
+ }
+
+} /* end of cuddBddExistAbstractRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Takes the exclusive OR of two BDDs and simultaneously abstracts the
+ variables in cube.]
+
+ Description [Takes the exclusive OR of two BDDs and simultaneously abstracts
+ the variables in cube. The variables are existentially abstracted. Returns a
+ pointer to the result is successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddAndAbstract]
+
+******************************************************************************/
+DdNode *
+cuddBddXorExistAbstractRecur(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * g,
+ DdNode * cube)
+{
+ DdNode *F, *fv, *fnv, *G, *gv, *gnv;
+ DdNode *one, *zero, *r, *t, *e, *Cube;
+ unsigned int topf, topg, topcube, top, index;
+
+ statLine(manager);
+ one = DD_ONE(manager);
+ zero = Cudd_Not(one);
+
+ /* Terminal cases. */
+ if (f == g) {
+ return(zero);
+ }
+ if (f == Cudd_Not(g)) {
+ return(one);
+ }
+ if (cube == one) {
+ return(cuddBddXorRecur(manager, f, g));
+ }
+ if (f == one) {
+ return(cuddBddExistAbstractRecur(manager, Cudd_Not(g), cube));
+ }
+ if (g == one) {
+ return(cuddBddExistAbstractRecur(manager, Cudd_Not(f), cube));
+ }
+ if (f == zero) {
+ return(cuddBddExistAbstractRecur(manager, g, cube));
+ }
+ if (g == zero) {
+ return(cuddBddExistAbstractRecur(manager, f, cube));
+ }
+
+ /* At this point f, g, and cube are not constant. */
+
+ if (f > g) { /* Try to increase cache efficiency. */
+ DdNode *tmp = f;
+ f = g;
+ g = tmp;
+ }
+
+ /* Check cache. */
+ r = cuddCacheLookup(manager, DD_BDD_XOR_EXIST_ABSTRACT_TAG, f, g, cube);
+ if (r != NULL) {
+ return(r);
+ }
+
+ /* Here we can skip the use of cuddI, because the operands are known
+ ** to be non-constant.
+ */
+ F = Cudd_Regular(f);
+ topf = manager->perm[F->index];
+ G = Cudd_Regular(g);
+ topg = manager->perm[G->index];
+ top = ddMin(topf, topg);
+ topcube = manager->perm[cube->index];
+
+ if (topcube < top) {
+ return(cuddBddXorExistAbstractRecur(manager, f, g, cuddT(cube)));
+ }
+ /* Now, topcube >= top. */
+
+ if (topf == top) {
+ index = F->index;
+ fv = cuddT(F);
+ fnv = cuddE(F);
+ if (Cudd_IsComplement(f)) {
+ fv = Cudd_Not(fv);
+ fnv = Cudd_Not(fnv);
+ }
+ } else {
+ index = G->index;
+ fv = fnv = f;
+ }
+
+ if (topg == top) {
+ gv = cuddT(G);
+ gnv = cuddE(G);
+ if (Cudd_IsComplement(g)) {
+ gv = Cudd_Not(gv);
+ gnv = Cudd_Not(gnv);
+ }
+ } else {
+ gv = gnv = g;
+ }
+
+ if (topcube == top) {
+ Cube = cuddT(cube);
+ } else {
+ Cube = cube;
+ }
+
+ t = cuddBddXorExistAbstractRecur(manager, fv, gv, Cube);
+ if (t == NULL) return(NULL);
+
+ /* Special case: 1 OR anything = 1. Hence, no need to compute
+ ** the else branch if t is 1.
+ */
+ if (t == one && topcube == top) {
+ cuddCacheInsert(manager, DD_BDD_XOR_EXIST_ABSTRACT_TAG, f, g, cube, one);
+ return(one);
+ }
+ cuddRef(t);
+
+ e = cuddBddXorExistAbstractRecur(manager, fnv, gnv, Cube);
+ if (e == NULL) {
+ Cudd_IterDerefBdd(manager, t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ if (topcube == top) { /* abstract */
+ r = cuddBddAndRecur(manager, Cudd_Not(t), Cudd_Not(e));
+ if (r == NULL) {
+ Cudd_IterDerefBdd(manager, t);
+ Cudd_IterDerefBdd(manager, e);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ cuddRef(r);
+ Cudd_IterDerefBdd(manager, t);
+ Cudd_IterDerefBdd(manager, e);
+ cuddDeref(r);
+ } else if (t == e) {
+ r = t;
+ cuddDeref(t);
+ cuddDeref(e);
+ } else {
+ if (Cudd_IsComplement(t)) {
+ r = cuddUniqueInter(manager,(int)index,Cudd_Not(t),Cudd_Not(e));
+ if (r == NULL) {
+ Cudd_IterDerefBdd(manager, t);
+ Cudd_IterDerefBdd(manager, e);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = cuddUniqueInter(manager,(int)index,t,e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(manager, t);
+ Cudd_IterDerefBdd(manager, e);
+ return(NULL);
+ }
+ }
+ cuddDeref(e);
+ cuddDeref(t);
+ }
+ cuddCacheInsert(manager, DD_BDD_XOR_EXIST_ABSTRACT_TAG, f, g, cube, r);
+ return (r);
+
+} /* end of cuddBddXorExistAbstractRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive steps of Cudd_bddBoleanDiff.]
+
+ Description [Performs the recursive steps of Cudd_bddBoleanDiff.
+ Returns the BDD obtained by XORing the cofactors of f with respect to
+ var if successful; NULL otherwise. Exploits the fact that dF/dx =
+ dF'/dx.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+cuddBddBooleanDiffRecur(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * var)
+{
+ DdNode *T, *E, *res, *res1, *res2;
+
+ statLine(manager);
+ if (cuddI(manager,f->index) > manager->perm[var->index]) {
+ /* f does not depend on var. */
+ return(Cudd_Not(DD_ONE(manager)));
+ }
+
+ /* From now on, f is non-constant. */
+
+ /* If the two indices are the same, so are their levels. */
+ if (f->index == var->index) {
+ res = cuddBddXorRecur(manager, cuddT(f), cuddE(f));
+ return(res);
+ }
+
+ /* From now on, cuddI(manager,f->index) < cuddI(manager,cube->index). */
+
+ /* Check the cache. */
+ res = cuddCacheLookup2(manager, cuddBddBooleanDiffRecur, f, var);
+ if (res != NULL) {
+ return(res);
+ }
+
+ /* Compute the cofactors of f. */
+ T = cuddT(f); E = cuddE(f);
+
+ res1 = cuddBddBooleanDiffRecur(manager, T, var);
+ if (res1 == NULL) return(NULL);
+ cuddRef(res1);
+ res2 = cuddBddBooleanDiffRecur(manager, Cudd_Regular(E), var);
+ if (res2 == NULL) {
+ Cudd_IterDerefBdd(manager, res1);
+ return(NULL);
+ }
+ cuddRef(res2);
+ /* ITE takes care of possible complementation of res1 and of the
+ ** case in which res1 == res2. */
+ res = cuddBddIteRecur(manager, manager->vars[f->index], res1, res2);
+ if (res == NULL) {
+ Cudd_IterDerefBdd(manager, res1);
+ Cudd_IterDerefBdd(manager, res2);
+ return(NULL);
+ }
+ cuddDeref(res1);
+ cuddDeref(res2);
+ cuddCacheInsert2(manager, cuddBddBooleanDiffRecur, f, var, res);
+ return(res);
+
+} /* end of cuddBddBooleanDiffRecur */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether cube is an BDD representing the product of
+ positive literals.]
+
+ Description [Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+bddCheckPositiveCube(
+ DdManager * manager,
+ DdNode * cube)
+{
+ if (Cudd_IsComplement(cube)) return(0);
+ if (cube == DD_ONE(manager)) return(1);
+ if (cuddIsConstant(cube)) return(0);
+ if (cuddE(cube) == Cudd_Not(DD_ONE(manager))) {
+ return(bddCheckPositiveCube(manager, cuddT(cube)));
+ }
+ return(0);
+
+} /* end of bddCheckPositiveCube */
+
diff --git a/src/bdd/cudd/cuddBddCorr.c b/src/bdd/cudd/cuddBddCorr.c
new file mode 100644
index 00000000..47395ec7
--- /dev/null
+++ b/src/bdd/cudd/cuddBddCorr.c
@@ -0,0 +1,481 @@
+/**CFile***********************************************************************
+
+ FileName [cuddBddCorr.c]
+
+ PackageName [cudd]
+
+ Synopsis [Correlation between BDDs.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_bddCorrelation()
+ <li> Cudd_bddCorrelationWeights()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> bddCorrelationAux()
+ <li> bddCorrelationWeightsAux()
+ <li> CorrelCompare()
+ <li> CorrelHash()
+ <li> CorrelCleanUp()
+ </ul>
+ ]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+typedef struct hashEntry {
+ DdNode *f;
+ DdNode *g;
+} HashEntry;
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddBddCorr.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+#ifdef CORREL_STATS
+static int num_calls;
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static double bddCorrelationAux ARGS((DdManager *dd, DdNode *f, DdNode *g, st_table *table));
+static double bddCorrelationWeightsAux ARGS((DdManager *dd, DdNode *f, DdNode *g, double *prob, st_table *table));
+static int CorrelCompare ARGS((const char *key1, const char *key2));
+static int CorrelHash ARGS((char *key, int modulus));
+static enum st_retval CorrelCleanUp ARGS((char *key, char *value, char *arg));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the correlation of f and g.]
+
+ Description [Computes the correlation of f and g. If f == g, their
+ correlation is 1. If f == g', their correlation is 0. Returns the
+ fraction of minterms in the ON-set of the EXNOR of f and g. If it
+ runs out of memory, returns (double)CUDD_OUT_OF_MEM.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddCorrelationWeights]
+
+******************************************************************************/
+double
+Cudd_bddCorrelation(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * g)
+{
+
+ st_table *table;
+ double correlation;
+
+#ifdef CORREL_STATS
+ num_calls = 0;
+#endif
+
+ table = st_init_table(CorrelCompare,CorrelHash);
+ if (table == NULL) return((double)CUDD_OUT_OF_MEM);
+ correlation = bddCorrelationAux(manager,f,g,table);
+ st_foreach(table, CorrelCleanUp, NIL(char));
+ st_free_table(table);
+ return(correlation);
+
+} /* end of Cudd_bddCorrelation */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the correlation of f and g for given input
+ probabilities.]
+
+ Description [Computes the correlation of f and g for given input
+ probabilities. On input, prob\[i\] is supposed to contain the
+ probability of the i-th input variable to be 1.
+ If f == g, their correlation is 1. If f == g', their
+ correlation is 0. Returns the probability that f and g have the same
+ value. If it runs out of memory, returns (double)CUDD_OUT_OF_MEM. The
+ correlation of f and the constant one gives the probability of f.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddCorrelation]
+
+******************************************************************************/
+double
+Cudd_bddCorrelationWeights(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * g,
+ double * prob)
+{
+
+ st_table *table;
+ double correlation;
+
+#ifdef CORREL_STATS
+ num_calls = 0;
+#endif
+
+ table = st_init_table(CorrelCompare,CorrelHash);
+ if (table == NULL) return((double)CUDD_OUT_OF_MEM);
+ correlation = bddCorrelationWeightsAux(manager,f,g,prob,table);
+ st_foreach(table, CorrelCleanUp, NIL(char));
+ st_free_table(table);
+ return(correlation);
+
+} /* end of Cudd_bddCorrelationWeights */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddCorrelation.]
+
+ Description [Performs the recursive step of Cudd_bddCorrelation.
+ Returns the fraction of minterms in the ON-set of the EXNOR of f and
+ g.]
+
+ SideEffects [None]
+
+ SeeAlso [bddCorrelationWeightsAux]
+
+******************************************************************************/
+static double
+bddCorrelationAux(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ st_table * table)
+{
+ DdNode *Fv, *Fnv, *G, *Gv, *Gnv;
+ double min, *pmin, min1, min2, *dummy;
+ HashEntry *entry;
+ unsigned int topF, topG;
+
+ statLine(dd);
+#ifdef CORREL_STATS
+ num_calls++;
+#endif
+
+ /* Terminal cases: only work for BDDs. */
+ if (f == g) return(1.0);
+ if (f == Cudd_Not(g)) return(0.0);
+
+ /* Standardize call using the following properties:
+ ** (f EXNOR g) = (g EXNOR f)
+ ** (f' EXNOR g') = (f EXNOR g).
+ */
+ if (f > g) {
+ DdNode *tmp = f;
+ f = g; g = tmp;
+ }
+ if (Cudd_IsComplement(f)) {
+ f = Cudd_Not(f);
+ g = Cudd_Not(g);
+ }
+ /* From now on, f is regular. */
+
+ entry = ALLOC(HashEntry,1);
+ if (entry == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(CUDD_OUT_OF_MEM);
+ }
+ entry->f = f; entry->g = g;
+
+ /* We do not use the fact that
+ ** correlation(f,g') = 1 - correlation(f,g)
+ ** to minimize the risk of cancellation.
+ */
+ if (st_lookup(table, (char *)entry, (char **)&dummy)) {
+ min = *dummy;
+ FREE(entry);
+ return(min);
+ }
+
+ G = Cudd_Regular(g);
+ topF = cuddI(dd,f->index); topG = cuddI(dd,G->index);
+ if (topF <= topG) { Fv = cuddT(f); Fnv = cuddE(f); } else { Fv = Fnv = f; }
+ if (topG <= topF) { Gv = cuddT(G); Gnv = cuddE(G); } else { Gv = Gnv = G; }
+
+ if (g != G) {
+ Gv = Cudd_Not(Gv);
+ Gnv = Cudd_Not(Gnv);
+ }
+
+ min1 = bddCorrelationAux(dd, Fv, Gv, table) / 2.0;
+ if (min1 == (double)CUDD_OUT_OF_MEM) {
+ FREE(entry);
+ return(CUDD_OUT_OF_MEM);
+ }
+ min2 = bddCorrelationAux(dd, Fnv, Gnv, table) / 2.0;
+ if (min2 == (double)CUDD_OUT_OF_MEM) {
+ FREE(entry);
+ return(CUDD_OUT_OF_MEM);
+ }
+ min = (min1+min2);
+
+ pmin = ALLOC(double,1);
+ if (pmin == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ *pmin = min;
+
+ if (st_insert(table,(char *)entry, (char *)pmin) == ST_OUT_OF_MEM) {
+ FREE(entry);
+ FREE(pmin);
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ return(min);
+
+} /* end of bddCorrelationAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddCorrelationWeigths.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [bddCorrelationAux]
+
+******************************************************************************/
+static double
+bddCorrelationWeightsAux(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ double * prob,
+ st_table * table)
+{
+ DdNode *Fv, *Fnv, *G, *Gv, *Gnv;
+ double min, *pmin, min1, min2, *dummy;
+ HashEntry *entry;
+ int topF, topG, index;
+
+ statLine(dd);
+#ifdef CORREL_STATS
+ num_calls++;
+#endif
+
+ /* Terminal cases: only work for BDDs. */
+ if (f == g) return(1.0);
+ if (f == Cudd_Not(g)) return(0.0);
+
+ /* Standardize call using the following properties:
+ ** (f EXNOR g) = (g EXNOR f)
+ ** (f' EXNOR g') = (f EXNOR g).
+ */
+ if (f > g) {
+ DdNode *tmp = f;
+ f = g; g = tmp;
+ }
+ if (Cudd_IsComplement(f)) {
+ f = Cudd_Not(f);
+ g = Cudd_Not(g);
+ }
+ /* From now on, f is regular. */
+
+ entry = ALLOC(HashEntry,1);
+ if (entry == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ entry->f = f; entry->g = g;
+
+ /* We do not use the fact that
+ ** correlation(f,g') = 1 - correlation(f,g)
+ ** to minimize the risk of cancellation.
+ */
+ if (st_lookup(table, (char *)entry, (char **)&dummy)) {
+ min = *dummy;
+ FREE(entry);
+ return(min);
+ }
+
+ G = Cudd_Regular(g);
+ topF = cuddI(dd,f->index); topG = cuddI(dd,G->index);
+ if (topF <= topG) {
+ Fv = cuddT(f); Fnv = cuddE(f);
+ index = f->index;
+ } else {
+ Fv = Fnv = f;
+ index = G->index;
+ }
+ if (topG <= topF) { Gv = cuddT(G); Gnv = cuddE(G); } else { Gv = Gnv = G; }
+
+ if (g != G) {
+ Gv = Cudd_Not(Gv);
+ Gnv = Cudd_Not(Gnv);
+ }
+
+ min1 = bddCorrelationWeightsAux(dd, Fv, Gv, prob, table) * prob[index];
+ if (min1 == (double)CUDD_OUT_OF_MEM) {
+ FREE(entry);
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ min2 = bddCorrelationWeightsAux(dd, Fnv, Gnv, prob, table) * (1.0 - prob[index]);
+ if (min2 == (double)CUDD_OUT_OF_MEM) {
+ FREE(entry);
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ min = (min1+min2);
+
+ pmin = ALLOC(double,1);
+ if (pmin == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ *pmin = min;
+
+ if (st_insert(table,(char *)entry, (char *)pmin) == ST_OUT_OF_MEM) {
+ FREE(entry);
+ FREE(pmin);
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ return(min);
+
+} /* end of bddCorrelationWeightsAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Compares two hash table entries.]
+
+ Description [Compares two hash table entries. Returns 0 if they are
+ identical; 1 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+CorrelCompare(
+ const char * key1,
+ const char * key2)
+{
+ HashEntry *entry1;
+ HashEntry *entry2;
+
+ entry1 = (HashEntry *) key1;
+ entry2 = (HashEntry *) key2;
+ if (entry1->f != entry2->f || entry1->g != entry2->g) return(1);
+
+ return(0);
+
+} /* end of CorrelCompare */
+
+
+/**Function********************************************************************
+
+ Synopsis [Hashes a hash table entry.]
+
+ Description [Hashes a hash table entry. It is patterned after
+ st_strhash. Returns a value between 0 and modulus.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+CorrelHash(
+ char * key,
+ int modulus)
+{
+ HashEntry *entry;
+ int val = 0;
+
+ entry = (HashEntry *) key;
+#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
+ val = ((int) ((long)entry->f))*997 + ((int) ((long)entry->g));
+#else
+ val = ((int) entry->f)*997 + ((int) entry->g);
+#endif
+
+ return ((val < 0) ? -val : val) % modulus;
+
+} /* end of CorrelHash */
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees memory associated with hash table.]
+
+ Description [Frees memory associated with hash table. Returns
+ ST_CONTINUE.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static enum st_retval
+CorrelCleanUp(
+ char * key,
+ char * value,
+ char * arg)
+{
+ double *d;
+ HashEntry *entry;
+
+ entry = (HashEntry *) key;
+ FREE(entry);
+ d = (double *)value;
+ FREE(d);
+ return ST_CONTINUE;
+
+} /* end of CorrelCleanUp */
+
diff --git a/src/bdd/cudd/cuddBddIte.c b/src/bdd/cudd/cuddBddIte.c
new file mode 100644
index 00000000..fe0c6500
--- /dev/null
+++ b/src/bdd/cudd/cuddBddIte.c
@@ -0,0 +1,1254 @@
+/**CFile***********************************************************************
+
+ FileName [cuddBddIte.c]
+
+ PackageName [cudd]
+
+ Synopsis [BDD ITE function and satellites.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_bddIte()
+ <li> Cudd_bddIteConstant()
+ <li> Cudd_bddIntersect()
+ <li> Cudd_bddAnd()
+ <li> Cudd_bddOr()
+ <li> Cudd_bddNand()
+ <li> Cudd_bddNor()
+ <li> Cudd_bddXor()
+ <li> Cudd_bddXnor()
+ <li> Cudd_bddLeq()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddBddIteRecur()
+ <li> cuddBddIntersectRecur()
+ <li> cuddBddAndRecur()
+ <li> cuddBddXorRecur()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> bddVarToConst()
+ <li> bddVarToCanonical()
+ <li> bddVarToCanonicalSimple()
+ </ul>]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddBddIte.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static void bddVarToConst ARGS((DdNode *f, DdNode **gp, DdNode **hp, DdNode *one));
+static int bddVarToCanonical ARGS((DdManager *dd, DdNode **fp, DdNode **gp, DdNode **hp, unsigned int *topfp, unsigned int *topgp, unsigned int *tophp));
+static int bddVarToCanonicalSimple ARGS((DdManager *dd, DdNode **fp, DdNode **gp, DdNode **hp, unsigned int *topfp, unsigned int *topgp, unsigned int *tophp));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements ITE(f,g,h).]
+
+ Description [Implements ITE(f,g,h). Returns a pointer to the
+ resulting BDD if successful; NULL if the intermediate result blows
+ up.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addIte Cudd_bddIteConstant Cudd_bddIntersect]
+
+******************************************************************************/
+DdNode *
+Cudd_bddIte(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ DdNode * h)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddIteRecur(dd,f,g,h);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddIte */
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements ITEconstant(f,g,h).]
+
+ Description [Implements ITEconstant(f,g,h). Returns a pointer to the
+ resulting BDD (which may or may not be constant) or DD_NON_CONSTANT.
+ No new nodes are created.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddIte Cudd_bddIntersect Cudd_bddLeq Cudd_addIteConstant]
+
+******************************************************************************/
+DdNode *
+Cudd_bddIteConstant(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ DdNode * h)
+{
+ DdNode *r, *Fv, *Fnv, *Gv, *Gnv, *H, *Hv, *Hnv, *t, *e;
+ DdNode *one = DD_ONE(dd);
+ DdNode *zero = Cudd_Not(one);
+ int comple;
+ unsigned int topf, topg, toph, v;
+
+ statLine(dd);
+ /* Trivial cases. */
+ if (f == one) /* ITE(1,G,H) => G */
+ return(g);
+
+ if (f == zero) /* ITE(0,G,H) => H */
+ return(h);
+
+ /* f now not a constant. */
+ bddVarToConst(f, &g, &h, one); /* possibly convert g or h */
+ /* to constants */
+
+ if (g == h) /* ITE(F,G,G) => G */
+ return(g);
+
+ if (Cudd_IsConstant(g) && Cudd_IsConstant(h))
+ return(DD_NON_CONSTANT); /* ITE(F,1,0) or ITE(F,0,1) */
+ /* => DD_NON_CONSTANT */
+
+ if (g == Cudd_Not(h))
+ return(DD_NON_CONSTANT); /* ITE(F,G,G') => DD_NON_CONSTANT */
+ /* if F != G and F != G' */
+
+ comple = bddVarToCanonical(dd, &f, &g, &h, &topf, &topg, &toph);
+
+ /* Cache lookup. */
+ r = cuddConstantLookup(dd, DD_BDD_ITE_CONSTANT_TAG, f, g, h);
+ if (r != NULL) {
+ return(Cudd_NotCond(r,comple && r != DD_NON_CONSTANT));
+ }
+
+ v = ddMin(topg, toph);
+
+ /* ITE(F,G,H) = (v,G,H) (non constant) if F = (v,1,0), v < top(G,H). */
+ if (topf < v && cuddT(f) == one && cuddE(f) == zero) {
+ return(DD_NON_CONSTANT);
+ }
+
+ /* Compute cofactors. */
+ if (topf <= v) {
+ v = ddMin(topf, v); /* v = top_var(F,G,H) */
+ Fv = cuddT(f); Fnv = cuddE(f);
+ } else {
+ Fv = Fnv = f;
+ }
+
+ if (topg == v) {
+ Gv = cuddT(g); Gnv = cuddE(g);
+ } else {
+ Gv = Gnv = g;
+ }
+
+ if (toph == v) {
+ H = Cudd_Regular(h);
+ Hv = cuddT(H); Hnv = cuddE(H);
+ if (Cudd_IsComplement(h)) {
+ Hv = Cudd_Not(Hv);
+ Hnv = Cudd_Not(Hnv);
+ }
+ } else {
+ Hv = Hnv = h;
+ }
+
+ /* Recursion. */
+ t = Cudd_bddIteConstant(dd, Fv, Gv, Hv);
+ if (t == DD_NON_CONSTANT || !Cudd_IsConstant(t)) {
+ cuddCacheInsert(dd, DD_BDD_ITE_CONSTANT_TAG, f, g, h, DD_NON_CONSTANT);
+ return(DD_NON_CONSTANT);
+ }
+ e = Cudd_bddIteConstant(dd, Fnv, Gnv, Hnv);
+ if (e == DD_NON_CONSTANT || !Cudd_IsConstant(e) || t != e) {
+ cuddCacheInsert(dd, DD_BDD_ITE_CONSTANT_TAG, f, g, h, DD_NON_CONSTANT);
+ return(DD_NON_CONSTANT);
+ }
+ cuddCacheInsert(dd, DD_BDD_ITE_CONSTANT_TAG, f, g, h, t);
+ return(Cudd_NotCond(t,comple));
+
+} /* end of Cudd_bddIteConstant */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns a function included in the intersection of f and g.]
+
+ Description [Computes a function included in the intersection of f and
+ g. (That is, a witness that the intersection is not empty.)
+ Cudd_bddIntersect tries to build as few new nodes as possible. If the
+ only result of interest is whether f and g intersect,
+ Cudd_bddLeq should be used instead.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddLeq Cudd_bddIteConstant]
+
+******************************************************************************/
+DdNode *
+Cudd_bddIntersect(
+ DdManager * dd /* manager */,
+ DdNode * f /* first operand */,
+ DdNode * g /* second operand */)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddIntersectRecur(dd,f,g);
+ } while (dd->reordered == 1);
+
+ return(res);
+
+} /* end of Cudd_bddIntersect */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the conjunction of two BDDs f and g.]
+
+ Description [Computes the conjunction of two BDDs f and g. Returns a
+ pointer to the resulting BDD if successful; NULL if the intermediate
+ result blows up.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddIte Cudd_addApply Cudd_bddAndAbstract Cudd_bddIntersect
+ Cudd_bddOr Cudd_bddNand Cudd_bddNor Cudd_bddXor Cudd_bddXnor]
+
+******************************************************************************/
+DdNode *
+Cudd_bddAnd(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddAndRecur(dd,f,g);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddAnd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the disjunction of two BDDs f and g.]
+
+ Description [Computes the disjunction of two BDDs f and g. Returns a
+ pointer to the resulting BDD if successful; NULL if the intermediate
+ result blows up.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddIte Cudd_addApply Cudd_bddAnd Cudd_bddNand Cudd_bddNor
+ Cudd_bddXor Cudd_bddXnor]
+
+******************************************************************************/
+DdNode *
+Cudd_bddOr(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddAndRecur(dd,Cudd_Not(f),Cudd_Not(g));
+ } while (dd->reordered == 1);
+ res = Cudd_NotCond(res,res != NULL);
+ return(res);
+
+} /* end of Cudd_bddOr */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the NAND of two BDDs f and g.]
+
+ Description [Computes the NAND of two BDDs f and g. Returns a
+ pointer to the resulting BDD if successful; NULL if the intermediate
+ result blows up.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddIte Cudd_addApply Cudd_bddAnd Cudd_bddOr Cudd_bddNor
+ Cudd_bddXor Cudd_bddXnor]
+
+******************************************************************************/
+DdNode *
+Cudd_bddNand(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddAndRecur(dd,f,g);
+ } while (dd->reordered == 1);
+ res = Cudd_NotCond(res,res != NULL);
+ return(res);
+
+} /* end of Cudd_bddNand */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the NOR of two BDDs f and g.]
+
+ Description [Computes the NOR of two BDDs f and g. Returns a
+ pointer to the resulting BDD if successful; NULL if the intermediate
+ result blows up.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddIte Cudd_addApply Cudd_bddAnd Cudd_bddOr Cudd_bddNand
+ Cudd_bddXor Cudd_bddXnor]
+
+******************************************************************************/
+DdNode *
+Cudd_bddNor(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddAndRecur(dd,Cudd_Not(f),Cudd_Not(g));
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddNor */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the exclusive OR of two BDDs f and g.]
+
+ Description [Computes the exclusive OR of two BDDs f and g. Returns a
+ pointer to the resulting BDD if successful; NULL if the intermediate
+ result blows up.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddIte Cudd_addApply Cudd_bddAnd Cudd_bddOr
+ Cudd_bddNand Cudd_bddNor Cudd_bddXnor]
+
+******************************************************************************/
+DdNode *
+Cudd_bddXor(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddXorRecur(dd,f,g);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddXor */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the exclusive NOR of two BDDs f and g.]
+
+ Description [Computes the exclusive NOR of two BDDs f and g. Returns a
+ pointer to the resulting BDD if successful; NULL if the intermediate
+ result blows up.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddIte Cudd_addApply Cudd_bddAnd Cudd_bddOr
+ Cudd_bddNand Cudd_bddNor Cudd_bddXor]
+
+******************************************************************************/
+DdNode *
+Cudd_bddXnor(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddXorRecur(dd,f,Cudd_Not(g));
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddXnor */
+
+
+/**Function********************************************************************
+
+ Synopsis [Determines whether f is less than or equal to g.]
+
+ Description [Returns 1 if f is less than or equal to g; 0 otherwise.
+ No new nodes are created.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddIteConstant Cudd_addEvalConst]
+
+******************************************************************************/
+int
+Cudd_bddLeq(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *one, *zero, *tmp, *F, *fv, *fvn, *gv, *gvn;
+ unsigned int topf, topg, res;
+
+ statLine(dd);
+ /* Terminal cases and normalization. */
+ if (f == g) return(1);
+
+ if (Cudd_IsComplement(g)) {
+ /* Special case: if f is regular and g is complemented,
+ ** f(1,...,1) = 1 > 0 = g(1,...,1).
+ */
+ if (!Cudd_IsComplement(f)) return(0);
+ /* Both are complemented: Swap and complement because
+ ** f <= g <=> g' <= f' and we want the second argument to be regular.
+ */
+ tmp = g;
+ g = Cudd_Not(f);
+ f = Cudd_Not(tmp);
+ } else if (Cudd_IsComplement(f) && g < f) {
+ tmp = g;
+ g = Cudd_Not(f);
+ f = Cudd_Not(tmp);
+ }
+
+ /* Now g is regular and, if f is not regular, f < g. */
+ one = DD_ONE(dd);
+ if (g == one) return(1); /* no need to test against zero */
+ if (f == one) return(0); /* since at this point g != one */
+ if (Cudd_Not(f) == g) return(0); /* because neither is constant */
+ zero = Cudd_Not(one);
+ if (f == zero) return(1);
+
+ /* Here neither f nor g is constant. */
+
+ /* Check cache. */
+ tmp = cuddCacheLookup2(dd,(DdNode * (*)(DdManager *, DdNode *,
+ DdNode *))Cudd_bddLeq,f,g);
+ if (tmp != NULL) {
+ return(tmp == one);
+ }
+
+ /* Compute cofactors. */
+ F = Cudd_Regular(f);
+ topf = dd->perm[F->index];
+ topg = dd->perm[g->index];
+ if (topf <= topg) {
+ fv = cuddT(F); fvn = cuddE(F);
+ if (f != F) {
+ fv = Cudd_Not(fv);
+ fvn = Cudd_Not(fvn);
+ }
+ } else {
+ fv = fvn = f;
+ }
+ if (topg <= topf) {
+ gv = cuddT(g); gvn = cuddE(g);
+ } else {
+ gv = gvn = g;
+ }
+
+ /* Recursive calls. Since we want to maximize the probability of
+ ** the special case f(1,...,1) > g(1,...,1), we consider the negative
+ ** cofactors first. Indeed, the complementation parity of the positive
+ ** cofactors is the same as the one of the parent functions.
+ */
+ res = Cudd_bddLeq(dd,fvn,gvn) && Cudd_bddLeq(dd,fv,gv);
+
+ /* Store result in cache and return. */
+ cuddCacheInsert2(dd,(DdNode * (*)(DdManager *, DdNode *, DdNode *))Cudd_bddLeq,f,g,(res ? one : zero));
+ return(res);
+
+} /* end of Cudd_bddLeq */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_bddIte.]
+
+ Description [Implements the recursive step of Cudd_bddIte. Returns a
+ pointer to the resulting BDD. NULL if the intermediate result blows
+ up or if reordering occurs.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+cuddBddIteRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ DdNode * h)
+{
+ DdNode *one, *zero, *res;
+ DdNode *r, *Fv, *Fnv, *Gv, *Gnv, *H, *Hv, *Hnv, *t, *e;
+ unsigned int topf, topg, toph, v;
+ int index;
+ int comple;
+
+ statLine(dd);
+ /* Terminal cases. */
+
+ /* One variable cases. */
+ if (f == (one = DD_ONE(dd))) /* ITE(1,G,H) = G */
+ return(g);
+
+ if (f == (zero = Cudd_Not(one))) /* ITE(0,G,H) = H */
+ return(h);
+
+ /* From now on, f is known not to be a constant. */
+ if (g == one || f == g) { /* ITE(F,F,H) = ITE(F,1,H) = F + H */
+ if (h == zero) { /* ITE(F,1,0) = F */
+ return(f);
+ } else {
+ res = cuddBddAndRecur(dd,Cudd_Not(f),Cudd_Not(h));
+ return(Cudd_NotCond(res,res != NULL));
+ }
+ } else if (g == zero || f == Cudd_Not(g)) { /* ITE(F,!F,H) = ITE(F,0,H) = !F * H */
+ if (h == one) { /* ITE(F,0,1) = !F */
+ return(Cudd_Not(f));
+ } else {
+ res = cuddBddAndRecur(dd,Cudd_Not(f),h);
+ return(res);
+ }
+ }
+ if (h == zero || f == h) { /* ITE(F,G,F) = ITE(F,G,0) = F * G */
+ res = cuddBddAndRecur(dd,f,g);
+ return(res);
+ } else if (h == one || f == Cudd_Not(h)) { /* ITE(F,G,!F) = ITE(F,G,1) = !F + G */
+ res = cuddBddAndRecur(dd,f,Cudd_Not(g));
+ return(Cudd_NotCond(res,res != NULL));
+ }
+
+ /* Check remaining one variable case. */
+ if (g == h) { /* ITE(F,G,G) = G */
+ return(g);
+ } else if (g == Cudd_Not(h)) { /* ITE(F,G,!G) = F <-> G */
+ res = cuddBddXorRecur(dd,f,h);
+ return(res);
+ }
+
+ /* From here, there are no constants. */
+ comple = bddVarToCanonicalSimple(dd, &f, &g, &h, &topf, &topg, &toph);
+
+ /* f & g are now regular pointers */
+
+ v = ddMin(topg, toph);
+
+ /* A shortcut: ITE(F,G,H) = (v,G,H) if F = (v,1,0), v < top(G,H). */
+ if (topf < v && cuddT(f) == one && cuddE(f) == zero) {
+ r = cuddUniqueInter(dd, (int) f->index, g, h);
+ return(Cudd_NotCond(r,comple && r != NULL));
+ }
+
+ /* Check cache. */
+ r = cuddCacheLookup(dd, DD_BDD_ITE_TAG, f, g, h);
+ if (r != NULL) {
+ return(Cudd_NotCond(r,comple));
+ }
+
+ /* Compute cofactors. */
+ if (topf <= v) {
+ v = ddMin(topf, v); /* v = top_var(F,G,H) */
+ index = f->index;
+ Fv = cuddT(f); Fnv = cuddE(f);
+ } else {
+ Fv = Fnv = f;
+ }
+ if (topg == v) {
+ index = g->index;
+ Gv = cuddT(g); Gnv = cuddE(g);
+ } else {
+ Gv = Gnv = g;
+ }
+ if (toph == v) {
+ H = Cudd_Regular(h);
+ index = H->index;
+ Hv = cuddT(H); Hnv = cuddE(H);
+ if (Cudd_IsComplement(h)) {
+ Hv = Cudd_Not(Hv);
+ Hnv = Cudd_Not(Hnv);
+ }
+ } else {
+ Hv = Hnv = h;
+ }
+
+ /* Recursive step. */
+ t = cuddBddIteRecur(dd,Fv,Gv,Hv);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+
+ e = cuddBddIteRecur(dd,Fnv,Gnv,Hnv);
+ if (e == NULL) {
+ Cudd_IterDerefBdd(dd,t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ r = (t == e) ? t : cuddUniqueInter(dd,index,t,e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd,t);
+ Cudd_IterDerefBdd(dd,e);
+ return(NULL);
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+
+ cuddCacheInsert(dd, DD_BDD_ITE_TAG, f, g, h, r);
+ return(Cudd_NotCond(r,comple));
+
+} /* end of cuddBddIteRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_bddIntersect.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddIntersect]
+
+******************************************************************************/
+DdNode *
+cuddBddIntersectRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res;
+ DdNode *F, *G, *t, *e;
+ DdNode *fv, *fnv, *gv, *gnv;
+ DdNode *one, *zero;
+ unsigned int index, topf, topg;
+
+ statLine(dd);
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+
+ /* Terminal cases. */
+ if (f == zero || g == zero || f == Cudd_Not(g)) return(zero);
+ if (f == g || g == one) return(f);
+ if (f == one) return(g);
+
+ /* At this point f and g are not constant. */
+ if (f > g) { DdNode *tmp = f; f = g; g = tmp; }
+ res = cuddCacheLookup2(dd,Cudd_bddIntersect,f,g);
+ if (res != NULL) return(res);
+
+ /* Find splitting variable. Here we can skip the use of cuddI,
+ ** because the operands are known to be non-constant.
+ */
+ F = Cudd_Regular(f);
+ topf = dd->perm[F->index];
+ G = Cudd_Regular(g);
+ topg = dd->perm[G->index];
+
+ /* Compute cofactors. */
+ if (topf <= topg) {
+ index = F->index;
+ fv = cuddT(F);
+ fnv = cuddE(F);
+ if (Cudd_IsComplement(f)) {
+ fv = Cudd_Not(fv);
+ fnv = Cudd_Not(fnv);
+ }
+ } else {
+ index = G->index;
+ fv = fnv = f;
+ }
+
+ if (topg <= topf) {
+ gv = cuddT(G);
+ gnv = cuddE(G);
+ if (Cudd_IsComplement(g)) {
+ gv = Cudd_Not(gv);
+ gnv = Cudd_Not(gnv);
+ }
+ } else {
+ gv = gnv = g;
+ }
+
+ /* Compute partial results. */
+ t = cuddBddIntersectRecur(dd,fv,gv);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ if (t != zero) {
+ e = zero;
+ } else {
+ e = cuddBddIntersectRecur(dd,fnv,gnv);
+ if (e == NULL) {
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ }
+ cuddRef(e);
+
+ if (t == e) { /* both equal zero */
+ res = t;
+ } else if (Cudd_IsComplement(t)) {
+ res = cuddUniqueInter(dd,(int)index,Cudd_Not(t),Cudd_Not(e));
+ if (res == NULL) {
+ Cudd_IterDerefBdd(dd, t);
+ Cudd_IterDerefBdd(dd, e);
+ return(NULL);
+ }
+ res = Cudd_Not(res);
+ } else {
+ res = cuddUniqueInter(dd,(int)index,t,e);
+ if (res == NULL) {
+ Cudd_IterDerefBdd(dd, t);
+ Cudd_IterDerefBdd(dd, e);
+ return(NULL);
+ }
+ }
+ cuddDeref(e);
+ cuddDeref(t);
+
+ cuddCacheInsert2(dd,Cudd_bddIntersect,f,g,res);
+
+ return(res);
+
+} /* end of cuddBddIntersectRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_bddAnd.]
+
+ Description [Implements the recursive step of Cudd_bddAnd by taking
+ the conjunction of two BDDs. Returns a pointer to the result is
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddAnd]
+
+******************************************************************************/
+DdNode *
+cuddBddAndRecur(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *F, *fv, *fnv, *G, *gv, *gnv;
+ DdNode *one, *r, *t, *e;
+ unsigned int topf, topg, index;
+
+ statLine(manager);
+ one = DD_ONE(manager);
+
+ /* Terminal cases. */
+ F = Cudd_Regular(f);
+ G = Cudd_Regular(g);
+ if (F == G) {
+ if (f == g) return(f);
+ else return(Cudd_Not(one));
+ }
+ if (F == one) {
+ if (f == one) return(g);
+ else return(f);
+ }
+ if (G == one) {
+ if (g == one) return(f);
+ else return(g);
+ }
+
+ /* At this point f and g are not constant. */
+ if (f > g) { /* Try to increase cache efficiency. */
+ DdNode *tmp = f;
+ f = g;
+ g = tmp;
+ F = Cudd_Regular(f);
+ G = Cudd_Regular(g);
+ }
+
+ /* Check cache. */
+ if (F->ref != 1 || G->ref != 1) {
+ r = cuddCacheLookup2(manager, Cudd_bddAnd, f, g);
+ if (r != NULL) return(r);
+ }
+
+ /* Here we can skip the use of cuddI, because the operands are known
+ ** to be non-constant.
+ */
+ topf = manager->perm[F->index];
+ topg = manager->perm[G->index];
+
+ /* Compute cofactors. */
+ if (topf <= topg) {
+ index = F->index;
+ fv = cuddT(F);
+ fnv = cuddE(F);
+ if (Cudd_IsComplement(f)) {
+ fv = Cudd_Not(fv);
+ fnv = Cudd_Not(fnv);
+ }
+ } else {
+ index = G->index;
+ fv = fnv = f;
+ }
+
+ if (topg <= topf) {
+ gv = cuddT(G);
+ gnv = cuddE(G);
+ if (Cudd_IsComplement(g)) {
+ gv = Cudd_Not(gv);
+ gnv = Cudd_Not(gnv);
+ }
+ } else {
+ gv = gnv = g;
+ }
+
+ t = cuddBddAndRecur(manager, fv, gv);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+
+ e = cuddBddAndRecur(manager, fnv, gnv);
+ if (e == NULL) {
+ Cudd_IterDerefBdd(manager, t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ if (t == e) {
+ r = t;
+ } else {
+ if (Cudd_IsComplement(t)) {
+ r = cuddUniqueInter(manager,(int)index,Cudd_Not(t),Cudd_Not(e));
+ if (r == NULL) {
+ Cudd_IterDerefBdd(manager, t);
+ Cudd_IterDerefBdd(manager, e);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = cuddUniqueInter(manager,(int)index,t,e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(manager, t);
+ Cudd_IterDerefBdd(manager, e);
+ return(NULL);
+ }
+ }
+ }
+ cuddDeref(e);
+ cuddDeref(t);
+ if (F->ref != 1 || G->ref != 1)
+ cuddCacheInsert2(manager, Cudd_bddAnd, f, g, r);
+ return(r);
+
+} /* end of cuddBddAndRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_bddXor.]
+
+ Description [Implements the recursive step of Cudd_bddXor by taking
+ the exclusive OR of two BDDs. Returns a pointer to the result is
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddXor]
+
+******************************************************************************/
+DdNode *
+cuddBddXorRecur(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *fv, *fnv, *G, *gv, *gnv;
+ DdNode *one, *zero, *r, *t, *e;
+ unsigned int topf, topg, index;
+
+ statLine(manager);
+ one = DD_ONE(manager);
+ zero = Cudd_Not(one);
+
+ /* Terminal cases. */
+ if (f == g) return(zero);
+ if (f == Cudd_Not(g)) return(one);
+ if (f > g) { /* Try to increase cache efficiency and simplify tests. */
+ DdNode *tmp = f;
+ f = g;
+ g = tmp;
+ }
+ if (g == zero) return(f);
+ if (g == one) return(Cudd_Not(f));
+ if (Cudd_IsComplement(f)) {
+ f = Cudd_Not(f);
+ g = Cudd_Not(g);
+ }
+ /* Now the first argument is regular. */
+ if (f == one) return(Cudd_Not(g));
+
+ /* At this point f and g are not constant. */
+
+ /* Check cache. */
+ r = cuddCacheLookup2(manager, Cudd_bddXor, f, g);
+ if (r != NULL) return(r);
+
+ /* Here we can skip the use of cuddI, because the operands are known
+ ** to be non-constant.
+ */
+ topf = manager->perm[f->index];
+ G = Cudd_Regular(g);
+ topg = manager->perm[G->index];
+
+ /* Compute cofactors. */
+ if (topf <= topg) {
+ index = f->index;
+ fv = cuddT(f);
+ fnv = cuddE(f);
+ } else {
+ index = G->index;
+ fv = fnv = f;
+ }
+
+ if (topg <= topf) {
+ gv = cuddT(G);
+ gnv = cuddE(G);
+ if (Cudd_IsComplement(g)) {
+ gv = Cudd_Not(gv);
+ gnv = Cudd_Not(gnv);
+ }
+ } else {
+ gv = gnv = g;
+ }
+
+ t = cuddBddXorRecur(manager, fv, gv);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+
+ e = cuddBddXorRecur(manager, fnv, gnv);
+ if (e == NULL) {
+ Cudd_IterDerefBdd(manager, t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ if (t == e) {
+ r = t;
+ } else {
+ if (Cudd_IsComplement(t)) {
+ r = cuddUniqueInter(manager,(int)index,Cudd_Not(t),Cudd_Not(e));
+ if (r == NULL) {
+ Cudd_IterDerefBdd(manager, t);
+ Cudd_IterDerefBdd(manager, e);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = cuddUniqueInter(manager,(int)index,t,e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(manager, t);
+ Cudd_IterDerefBdd(manager, e);
+ return(NULL);
+ }
+ }
+ }
+ cuddDeref(e);
+ cuddDeref(t);
+ cuddCacheInsert2(manager, Cudd_bddXor, f, g, r);
+ return(r);
+
+} /* end of cuddBddXorRecur */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Replaces variables with constants if possible.]
+
+ Description [This function performs part of the transformation to
+ standard form by replacing variables with constants if possible.]
+
+ SideEffects [None]
+
+ SeeAlso [bddVarToCanonical bddVarToCanonicalSimple]
+
+******************************************************************************/
+static void
+bddVarToConst(
+ DdNode * f,
+ DdNode ** gp,
+ DdNode ** hp,
+ DdNode * one)
+{
+ DdNode *g = *gp;
+ DdNode *h = *hp;
+
+ if (f == g) { /* ITE(F,F,H) = ITE(F,1,H) = F + H */
+ *gp = one;
+ } else if (f == Cudd_Not(g)) { /* ITE(F,!F,H) = ITE(F,0,H) = !F * H */
+ *gp = Cudd_Not(one);
+ }
+ if (f == h) { /* ITE(F,G,F) = ITE(F,G,0) = F * G */
+ *hp = Cudd_Not(one);
+ } else if (f == Cudd_Not(h)) { /* ITE(F,G,!F) = ITE(F,G,1) = !F + G */
+ *hp = one;
+ }
+
+} /* end of bddVarToConst */
+
+
+/**Function********************************************************************
+
+ Synopsis [Picks unique member from equiv expressions.]
+
+ Description [Reduces 2 variable expressions to canonical form.]
+
+ SideEffects [None]
+
+ SeeAlso [bddVarToConst bddVarToCanonicalSimple]
+
+******************************************************************************/
+static int
+bddVarToCanonical(
+ DdManager * dd,
+ DdNode ** fp,
+ DdNode ** gp,
+ DdNode ** hp,
+ unsigned int * topfp,
+ unsigned int * topgp,
+ unsigned int * tophp)
+{
+ register DdNode *F, *G, *H, *r, *f, *g, *h;
+ register unsigned int topf, topg, toph;
+ DdNode *one = dd->one;
+ int comple, change;
+
+ f = *fp;
+ g = *gp;
+ h = *hp;
+ F = Cudd_Regular(f);
+ G = Cudd_Regular(g);
+ H = Cudd_Regular(h);
+ topf = cuddI(dd,F->index);
+ topg = cuddI(dd,G->index);
+ toph = cuddI(dd,H->index);
+
+ change = 0;
+
+ if (G == one) { /* ITE(F,c,H) */
+ if ((topf > toph) || (topf == toph && f > h)) {
+ r = h;
+ h = f;
+ f = r; /* ITE(F,1,H) = ITE(H,1,F) */
+ if (g != one) { /* g == zero */
+ f = Cudd_Not(f); /* ITE(F,0,H) = ITE(!H,0,!F) */
+ h = Cudd_Not(h);
+ }
+ change = 1;
+ }
+ } else if (H == one) { /* ITE(F,G,c) */
+ if ((topf > topg) || (topf == topg && f > g)) {
+ r = g;
+ g = f;
+ f = r; /* ITE(F,G,0) = ITE(G,F,0) */
+ if (h == one) {
+ f = Cudd_Not(f); /* ITE(F,G,1) = ITE(!G,!F,1) */
+ g = Cudd_Not(g);
+ }
+ change = 1;
+ }
+ } else if (g == Cudd_Not(h)) { /* ITE(F,G,!G) = ITE(G,F,!F) */
+ if ((topf > topg) || (topf == topg && f > g)) {
+ r = f;
+ f = g;
+ g = r;
+ h = Cudd_Not(r);
+ change = 1;
+ }
+ }
+ /* adjust pointers so that the first 2 arguments to ITE are regular */
+ if (Cudd_IsComplement(f) != 0) { /* ITE(!F,G,H) = ITE(F,H,G) */
+ f = Cudd_Not(f);
+ r = g;
+ g = h;
+ h = r;
+ change = 1;
+ }
+ comple = 0;
+ if (Cudd_IsComplement(g) != 0) { /* ITE(F,!G,H) = !ITE(F,G,!H) */
+ g = Cudd_Not(g);
+ h = Cudd_Not(h);
+ change = 1;
+ comple = 1;
+ }
+ if (change != 0) {
+ *fp = f;
+ *gp = g;
+ *hp = h;
+ }
+ *topfp = cuddI(dd,f->index);
+ *topgp = cuddI(dd,g->index);
+ *tophp = cuddI(dd,Cudd_Regular(h)->index);
+
+ return(comple);
+
+} /* end of bddVarToCanonical */
+
+
+/**Function********************************************************************
+
+ Synopsis [Picks unique member from equiv expressions.]
+
+ Description [Makes sure the first two pointers are regular. This
+ mat require the complementation of the result, which is signaled by
+ returning 1 instead of 0. This function is simpler than the general
+ case because it assumes that no two arguments are the same or
+ complementary, and no argument is constant.]
+
+ SideEffects [None]
+
+ SeeAlso [bddVarToConst bddVarToCanonical]
+
+******************************************************************************/
+static int
+bddVarToCanonicalSimple(
+ DdManager * dd,
+ DdNode ** fp,
+ DdNode ** gp,
+ DdNode ** hp,
+ unsigned int * topfp,
+ unsigned int * topgp,
+ unsigned int * tophp)
+{
+ register DdNode *r, *f, *g, *h;
+ int comple, change;
+
+ f = *fp;
+ g = *gp;
+ h = *hp;
+
+ change = 0;
+
+ /* adjust pointers so that the first 2 arguments to ITE are regular */
+ if (Cudd_IsComplement(f)) { /* ITE(!F,G,H) = ITE(F,H,G) */
+ f = Cudd_Not(f);
+ r = g;
+ g = h;
+ h = r;
+ change = 1;
+ }
+ comple = 0;
+ if (Cudd_IsComplement(g)) { /* ITE(F,!G,H) = !ITE(F,G,!H) */
+ g = Cudd_Not(g);
+ h = Cudd_Not(h);
+ change = 1;
+ comple = 1;
+ }
+ if (change) {
+ *fp = f;
+ *gp = g;
+ *hp = h;
+ }
+
+ /* Here we can skip the use of cuddI, because the operands are known
+ ** to be non-constant.
+ */
+ *topfp = dd->perm[f->index];
+ *topgp = dd->perm[g->index];
+ *tophp = dd->perm[Cudd_Regular(h)->index];
+
+ return(comple);
+
+} /* end of bddVarToCanonicalSimple */
+
diff --git a/src/bdd/cudd/cuddBridge.c b/src/bdd/cudd/cuddBridge.c
new file mode 100644
index 00000000..e7e5c89f
--- /dev/null
+++ b/src/bdd/cudd/cuddBridge.c
@@ -0,0 +1,981 @@
+/**CFile***********************************************************************
+
+ FileName [cuddBridge.c]
+
+ PackageName [cudd]
+
+ Synopsis [Translation from BDD to ADD and vice versa and transfer between
+ different managers.]
+
+ Description [External procedures included in this file:
+ <ul>
+ <li> Cudd_addBddThreshold()
+ <li> Cudd_addBddStrictThreshold()
+ <li> Cudd_addBddInterval()
+ <li> Cudd_addBddIthBit()
+ <li> Cudd_BddToAdd()
+ <li> Cudd_addBddPattern()
+ <li> Cudd_bddTransfer()
+ </ul>
+ Internal procedures included in this file:
+ <ul>
+ <li> cuddBddTransfer()
+ <li> cuddAddBddDoPattern()
+ </ul>
+ Static procedures included in this file:
+ <ul>
+ <li> addBddDoThreshold()
+ <li> addBddDoStrictThreshold()
+ <li> addBddDoInterval()
+ <li> addBddDoIthBit()
+ <li> ddBddToAddRecur()
+ <li> cuddBddTransferRecur()
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddBridge.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static DdNode * addBddDoThreshold ARGS((DdManager *dd, DdNode *f, DdNode *val));
+static DdNode * addBddDoStrictThreshold ARGS((DdManager *dd, DdNode *f, DdNode *val));
+static DdNode * addBddDoInterval ARGS((DdManager *dd, DdNode *f, DdNode *l, DdNode *u));
+static DdNode * addBddDoIthBit ARGS((DdManager *dd, DdNode *f, DdNode *index));
+static DdNode * ddBddToAddRecur ARGS((DdManager *dd, DdNode *B));
+static DdNode * cuddBddTransferRecur ARGS((DdManager *ddS, DdManager *ddD, DdNode *f, st_table *table));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Converts an ADD to a BDD.]
+
+ Description [Converts an ADD to a BDD by replacing all
+ discriminants greater than or equal to value with 1, and all other
+ discriminants with 0. Returns a pointer to the resulting BDD if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addBddInterval Cudd_addBddPattern Cudd_BddToAdd
+ Cudd_addBddStrictThreshold]
+
+******************************************************************************/
+DdNode *
+Cudd_addBddThreshold(
+ DdManager * dd,
+ DdNode * f,
+ CUDD_VALUE_TYPE value)
+{
+ DdNode *res;
+ DdNode *val;
+
+ val = cuddUniqueConst(dd,value);
+ if (val == NULL) return(NULL);
+ cuddRef(val);
+
+ do {
+ dd->reordered = 0;
+ res = addBddDoThreshold(dd, f, val);
+ } while (dd->reordered == 1);
+
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, val);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd, val);
+ cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_addBddThreshold */
+
+
+/**Function********************************************************************
+
+ Synopsis [Converts an ADD to a BDD.]
+
+ Description [Converts an ADD to a BDD by replacing all
+ discriminants STRICTLY greater than value with 1, and all other
+ discriminants with 0. Returns a pointer to the resulting BDD if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addBddInterval Cudd_addBddPattern Cudd_BddToAdd
+ Cudd_addBddThreshold]
+
+******************************************************************************/
+DdNode *
+Cudd_addBddStrictThreshold(
+ DdManager * dd,
+ DdNode * f,
+ CUDD_VALUE_TYPE value)
+{
+ DdNode *res;
+ DdNode *val;
+
+ val = cuddUniqueConst(dd,value);
+ if (val == NULL) return(NULL);
+ cuddRef(val);
+
+ do {
+ dd->reordered = 0;
+ res = addBddDoStrictThreshold(dd, f, val);
+ } while (dd->reordered == 1);
+
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, val);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd, val);
+ cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_addBddStrictThreshold */
+
+
+/**Function********************************************************************
+
+ Synopsis [Converts an ADD to a BDD.]
+
+ Description [Converts an ADD to a BDD by replacing all
+ discriminants greater than or equal to lower and less than or equal to
+ upper with 1, and all other discriminants with 0. Returns a pointer to
+ the resulting BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addBddThreshold Cudd_addBddStrictThreshold
+ Cudd_addBddPattern Cudd_BddToAdd]
+
+******************************************************************************/
+DdNode *
+Cudd_addBddInterval(
+ DdManager * dd,
+ DdNode * f,
+ CUDD_VALUE_TYPE lower,
+ CUDD_VALUE_TYPE upper)
+{
+ DdNode *res;
+ DdNode *l;
+ DdNode *u;
+
+ /* Create constant nodes for the interval bounds, so that we can use
+ ** the global cache.
+ */
+ l = cuddUniqueConst(dd,lower);
+ if (l == NULL) return(NULL);
+ cuddRef(l);
+ u = cuddUniqueConst(dd,upper);
+ if (u == NULL) {
+ Cudd_RecursiveDeref(dd,l);
+ return(NULL);
+ }
+ cuddRef(u);
+
+ do {
+ dd->reordered = 0;
+ res = addBddDoInterval(dd, f, l, u);
+ } while (dd->reordered == 1);
+
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, l);
+ Cudd_RecursiveDeref(dd, u);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd, l);
+ Cudd_RecursiveDeref(dd, u);
+ cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_addBddInterval */
+
+
+/**Function********************************************************************
+
+ Synopsis [Converts an ADD to a BDD by extracting the i-th bit from
+ the leaves.]
+
+ Description [Converts an ADD to a BDD by replacing all
+ discriminants whose i-th bit is equal to 1 with 1, and all other
+ discriminants with 0. The i-th bit refers to the integer
+ representation of the leaf value. If the value is has a fractional
+ part, it is ignored. Repeated calls to this procedure allow one to
+ transform an integer-valued ADD into an array of BDDs, one for each
+ bit of the leaf values. Returns a pointer to the resulting BDD if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addBddInterval Cudd_addBddPattern Cudd_BddToAdd]
+
+******************************************************************************/
+DdNode *
+Cudd_addBddIthBit(
+ DdManager * dd,
+ DdNode * f,
+ int bit)
+{
+ DdNode *res;
+ DdNode *index;
+
+ index = cuddUniqueConst(dd,(CUDD_VALUE_TYPE) bit);
+ if (index == NULL) return(NULL);
+ cuddRef(index);
+
+ do {
+ dd->reordered = 0;
+ res = addBddDoIthBit(dd, f, index);
+ } while (dd->reordered == 1);
+
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, index);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd, index);
+ cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_addBddIthBit */
+
+
+/**Function********************************************************************
+
+ Synopsis [Converts a BDD to a 0-1 ADD.]
+
+ Description [Converts a BDD to a 0-1 ADD. Returns a pointer to the
+ resulting ADD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addBddPattern Cudd_addBddThreshold Cudd_addBddInterval
+ Cudd_addBddStrictThreshold]
+
+******************************************************************************/
+DdNode *
+Cudd_BddToAdd(
+ DdManager * dd,
+ DdNode * B)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = ddBddToAddRecur(dd, B);
+ } while (dd->reordered ==1);
+ return(res);
+
+} /* end of Cudd_BddToAdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Converts an ADD to a BDD.]
+
+ Description [Converts an ADD to a BDD by replacing all
+ discriminants different from 0 with 1. Returns a pointer to the
+ resulting BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_BddToAdd Cudd_addBddThreshold Cudd_addBddInterval
+ Cudd_addBddStrictThreshold]
+
+******************************************************************************/
+DdNode *
+Cudd_addBddPattern(
+ DdManager * dd,
+ DdNode * f)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddAddBddDoPattern(dd, f);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_addBddPattern */
+
+
+/**Function********************************************************************
+
+ Synopsis [Convert a BDD from a manager to another one.]
+
+ Description [Convert a BDD from a manager to another one. The orders of the
+ variables in the two managers may be different. Returns a
+ pointer to the BDD in the destination manager if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_bddTransfer(
+ DdManager * ddSource,
+ DdManager * ddDestination,
+ DdNode * f)
+{
+ DdNode *res;
+ do {
+ ddDestination->reordered = 0;
+ res = cuddBddTransfer(ddSource, ddDestination, f);
+ } while (ddDestination->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddTransfer */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Convert a BDD from a manager to another one.]
+
+ Description [Convert a BDD from a manager to another one. Returns a
+ pointer to the BDD in the destination manager if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddTransfer]
+
+******************************************************************************/
+DdNode *
+cuddBddTransfer(
+ DdManager * ddS,
+ DdManager * ddD,
+ DdNode * f)
+{
+ DdNode *res;
+ st_table *table = NULL;
+ st_generator *gen = NULL;
+ DdNode *key, *value;
+
+ table = st_init_table(st_ptrcmp,st_ptrhash);
+ if (table == NULL) goto failure;
+ res = cuddBddTransferRecur(ddS, ddD, f, table);
+ if (res != NULL) cuddRef(res);
+
+ /* Dereference all elements in the table and dispose of the table.
+ ** This must be done also if res is NULL to avoid leaks in case of
+ ** reordering. */
+ gen = st_init_gen(table);
+ if (gen == NULL) goto failure;
+ while (st_gen(gen, (char **) &key, (char **) &value)) {
+ Cudd_RecursiveDeref(ddD, value);
+ }
+ st_free_gen(gen); gen = NULL;
+ st_free_table(table); table = NULL;
+
+ if (res != NULL) cuddDeref(res);
+ return(res);
+
+failure:
+ if (table != NULL) st_free_table(table);
+ if (gen != NULL) st_free_gen(gen);
+ return(NULL);
+
+} /* end of cuddBddTransfer */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step for Cudd_addBddPattern.]
+
+ Description [Performs the recursive step for Cudd_addBddPattern. Returns a
+ pointer to the resulting BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+cuddAddBddDoPattern(
+ DdManager * dd,
+ DdNode * f)
+{
+ DdNode *res, *T, *E;
+ DdNode *fv, *fvn;
+ int v;
+
+ statLine(dd);
+ /* Check terminal case. */
+ if (cuddIsConstant(f)) {
+ return(Cudd_NotCond(DD_ONE(dd),f == DD_ZERO(dd)));
+ }
+
+ /* Check cache. */
+ res = cuddCacheLookup1(dd,Cudd_addBddPattern,f);
+ if (res != NULL) return(res);
+
+ /* Recursive step. */
+ v = f->index;
+ fv = cuddT(f); fvn = cuddE(f);
+
+ T = cuddAddBddDoPattern(dd,fv);
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+
+ E = cuddAddBddDoPattern(dd,fvn);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ return(NULL);
+ }
+ cuddRef(E);
+ if (Cudd_IsComplement(T)) {
+ res = (T == E) ? Cudd_Not(T) : cuddUniqueInter(dd,v,Cudd_Not(T),Cudd_Not(E));
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ res = Cudd_Not(res);
+ } else {
+ res = (T == E) ? T : cuddUniqueInter(dd,v,T,E);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ }
+ cuddDeref(T);
+ cuddDeref(E);
+
+ /* Store result. */
+ cuddCacheInsert1(dd,Cudd_addBddPattern,f,res);
+
+ return(res);
+
+} /* end of cuddAddBddDoPattern */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step for Cudd_addBddThreshold.]
+
+ Description [Performs the recursive step for Cudd_addBddThreshold.
+ Returns a pointer to the BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [addBddDoStrictThreshold]
+
+******************************************************************************/
+static DdNode *
+addBddDoThreshold(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * val)
+{
+ DdNode *res, *T, *E;
+ DdNode *fv, *fvn;
+ int v;
+
+ statLine(dd);
+ /* Check terminal case. */
+ if (cuddIsConstant(f)) {
+ return(Cudd_NotCond(DD_ONE(dd),cuddV(f) < cuddV(val)));
+ }
+
+ /* Check cache. */
+ res = cuddCacheLookup2(dd,addBddDoThreshold,f,val);
+ if (res != NULL) return(res);
+
+ /* Recursive step. */
+ v = f->index;
+ fv = cuddT(f); fvn = cuddE(f);
+
+ T = addBddDoThreshold(dd,fv,val);
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+
+ E = addBddDoThreshold(dd,fvn,val);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ return(NULL);
+ }
+ cuddRef(E);
+ if (Cudd_IsComplement(T)) {
+ res = (T == E) ? Cudd_Not(T) : cuddUniqueInter(dd,v,Cudd_Not(T),Cudd_Not(E));
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ res = Cudd_Not(res);
+ } else {
+ res = (T == E) ? T : cuddUniqueInter(dd,v,T,E);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ }
+ cuddDeref(T);
+ cuddDeref(E);
+
+ /* Store result. */
+ cuddCacheInsert2(dd,addBddDoThreshold,f,val,res);
+
+ return(res);
+
+} /* end of addBddDoThreshold */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step for Cudd_addBddStrictThreshold.]
+
+ Description [Performs the recursive step for Cudd_addBddStrictThreshold.
+ Returns a pointer to the BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [addBddDoThreshold]
+
+******************************************************************************/
+static DdNode *
+addBddDoStrictThreshold(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * val)
+{
+ DdNode *res, *T, *E;
+ DdNode *fv, *fvn;
+ int v;
+
+ statLine(dd);
+ /* Check terminal case. */
+ if (cuddIsConstant(f)) {
+ return(Cudd_NotCond(DD_ONE(dd),cuddV(f) <= cuddV(val)));
+ }
+
+ /* Check cache. */
+ res = cuddCacheLookup2(dd,addBddDoStrictThreshold,f,val);
+ if (res != NULL) return(res);
+
+ /* Recursive step. */
+ v = f->index;
+ fv = cuddT(f); fvn = cuddE(f);
+
+ T = addBddDoStrictThreshold(dd,fv,val);
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+
+ E = addBddDoStrictThreshold(dd,fvn,val);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ return(NULL);
+ }
+ cuddRef(E);
+ if (Cudd_IsComplement(T)) {
+ res = (T == E) ? Cudd_Not(T) : cuddUniqueInter(dd,v,Cudd_Not(T),Cudd_Not(E));
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ res = Cudd_Not(res);
+ } else {
+ res = (T == E) ? T : cuddUniqueInter(dd,v,T,E);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ }
+ cuddDeref(T);
+ cuddDeref(E);
+
+ /* Store result. */
+ cuddCacheInsert2(dd,addBddDoStrictThreshold,f,val,res);
+
+ return(res);
+
+} /* end of addBddDoStrictThreshold */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step for Cudd_addBddInterval.]
+
+ Description [Performs the recursive step for Cudd_addBddInterval.
+ Returns a pointer to the BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [addBddDoThreshold addBddDoStrictThreshold]
+
+******************************************************************************/
+static DdNode *
+addBddDoInterval(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * l,
+ DdNode * u)
+{
+ DdNode *res, *T, *E;
+ DdNode *fv, *fvn;
+ int v;
+
+ statLine(dd);
+ /* Check terminal case. */
+ if (cuddIsConstant(f)) {
+ return(Cudd_NotCond(DD_ONE(dd),cuddV(f) < cuddV(l) || cuddV(f) > cuddV(u)));
+ }
+
+ /* Check cache. */
+ res = cuddCacheLookup(dd,DD_ADD_BDD_DO_INTERVAL_TAG,f,l,u);
+ if (res != NULL) return(res);
+
+ /* Recursive step. */
+ v = f->index;
+ fv = cuddT(f); fvn = cuddE(f);
+
+ T = addBddDoInterval(dd,fv,l,u);
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+
+ E = addBddDoInterval(dd,fvn,l,u);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ return(NULL);
+ }
+ cuddRef(E);
+ if (Cudd_IsComplement(T)) {
+ res = (T == E) ? Cudd_Not(T) : cuddUniqueInter(dd,v,Cudd_Not(T),Cudd_Not(E));
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ res = Cudd_Not(res);
+ } else {
+ res = (T == E) ? T : cuddUniqueInter(dd,v,T,E);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ }
+ cuddDeref(T);
+ cuddDeref(E);
+
+ /* Store result. */
+ cuddCacheInsert(dd,DD_ADD_BDD_DO_INTERVAL_TAG,f,l,u,res);
+
+ return(res);
+
+} /* end of addBddDoInterval */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step for Cudd_addBddIthBit.]
+
+ Description [Performs the recursive step for Cudd_addBddIthBit.
+ Returns a pointer to the BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+addBddDoIthBit(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * index)
+{
+ DdNode *res, *T, *E;
+ DdNode *fv, *fvn;
+ int mask, value;
+ int v;
+
+ statLine(dd);
+ /* Check terminal case. */
+ if (cuddIsConstant(f)) {
+ mask = 1 << ((int) cuddV(index));
+ value = (int) cuddV(f);
+ return(Cudd_NotCond(DD_ONE(dd),(value & mask) == 0));
+ }
+
+ /* Check cache. */
+ res = cuddCacheLookup2(dd,addBddDoIthBit,f,index);
+ if (res != NULL) return(res);
+
+ /* Recursive step. */
+ v = f->index;
+ fv = cuddT(f); fvn = cuddE(f);
+
+ T = addBddDoIthBit(dd,fv,index);
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+
+ E = addBddDoIthBit(dd,fvn,index);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ return(NULL);
+ }
+ cuddRef(E);
+ if (Cudd_IsComplement(T)) {
+ res = (T == E) ? Cudd_Not(T) : cuddUniqueInter(dd,v,Cudd_Not(T),Cudd_Not(E));
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ res = Cudd_Not(res);
+ } else {
+ res = (T == E) ? T : cuddUniqueInter(dd,v,T,E);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ }
+ cuddDeref(T);
+ cuddDeref(E);
+
+ /* Store result. */
+ cuddCacheInsert2(dd,addBddDoIthBit,f,index,res);
+
+ return(res);
+
+} /* end of addBddDoIthBit */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step for Cudd_BddToAdd.]
+
+ Description [Performs the recursive step for Cudd_BddToAdd. Returns a
+ pointer to the resulting ADD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+ddBddToAddRecur(
+ DdManager * dd,
+ DdNode * B)
+{
+ DdNode *one;
+ DdNode *res, *res1, *T, *E, *Bt, *Be;
+ int complement = 0;
+
+ statLine(dd);
+ one = DD_ONE(dd);
+
+ if (Cudd_IsConstant(B)) {
+ if (B == one) {
+ res = one;
+ } else {
+ res = DD_ZERO(dd);
+ }
+ return(res);
+ }
+ /* Check visited table */
+ res = cuddCacheLookup1(dd,ddBddToAddRecur,B);
+ if (res != NULL) return(res);
+
+ if (Cudd_IsComplement(B)) {
+ complement = 1;
+ Bt = cuddT(Cudd_Regular(B));
+ Be = cuddE(Cudd_Regular(B));
+ } else {
+ Bt = cuddT(B);
+ Be = cuddE(B);
+ }
+
+ T = ddBddToAddRecur(dd, Bt);
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+
+ E = ddBddToAddRecur(dd, Be);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ return(NULL);
+ }
+ cuddRef(E);
+
+ /* No need to check for T == E, because it is guaranteed not to happen. */
+ res = cuddUniqueInter(dd, (int) Cudd_Regular(B)->index, T, E);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd ,T);
+ Cudd_RecursiveDeref(dd ,E);
+ return(NULL);
+ }
+ cuddDeref(T);
+ cuddDeref(E);
+
+ if (complement) {
+ cuddRef(res);
+ res1 = cuddAddCmplRecur(dd, res);
+ if (res1 == NULL) {
+ Cudd_RecursiveDeref(dd, res);
+ return(NULL);
+ }
+ cuddRef(res1);
+ Cudd_RecursiveDeref(dd, res);
+ res = res1;
+ cuddDeref(res);
+ }
+
+ /* Store result. */
+ cuddCacheInsert1(dd,ddBddToAddRecur,B,res);
+
+ return(res);
+
+} /* end of ddBddToAddRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddTransfer.]
+
+ Description [Performs the recursive step of Cudd_bddTransfer.
+ Returns a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddBddTransfer]
+
+******************************************************************************/
+static DdNode *
+cuddBddTransferRecur(
+ DdManager * ddS,
+ DdManager * ddD,
+ DdNode * f,
+ st_table * table)
+{
+ DdNode *ft, *fe, *t, *e, *var, *res;
+ DdNode *one, *zero;
+ int index;
+ int comple = 0;
+
+ statLine(ddD);
+ one = DD_ONE(ddD);
+ comple = Cudd_IsComplement(f);
+
+ /* Trivial cases. */
+ if (Cudd_IsConstant(f)) return(Cudd_NotCond(one, comple));
+
+ /* Make canonical to increase the utilization of the cache. */
+ f = Cudd_NotCond(f,comple);
+ /* Now f is a regular pointer to a non-constant node. */
+
+ /* Check the cache. */
+ if(st_lookup(table, (char *)f, (char **) &res))
+ return(Cudd_NotCond(res,comple));
+
+ /* Recursive step. */
+ index = f->index;
+ ft = cuddT(f); fe = cuddE(f);
+
+ t = cuddBddTransferRecur(ddS, ddD, ft, table);
+ if (t == NULL) {
+ return(NULL);
+ }
+ cuddRef(t);
+
+ e = cuddBddTransferRecur(ddS, ddD, fe, table);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(ddD, t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ zero = Cudd_Not(one);
+ var = cuddUniqueInter(ddD,index,one,zero);
+ if (var == NULL) {
+ Cudd_RecursiveDeref(ddD, t);
+ Cudd_RecursiveDeref(ddD, e);
+ return(NULL);
+ }
+ res = cuddBddIteRecur(ddD,var,t,e);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(ddD, t);
+ Cudd_RecursiveDeref(ddD, e);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(ddD, t);
+ Cudd_RecursiveDeref(ddD, e);
+
+ if (st_add_direct(table, (char *) f, (char *) res) == ST_OUT_OF_MEM) {
+ Cudd_RecursiveDeref(ddD, res);
+ return(NULL);
+ }
+ return(Cudd_NotCond(res,comple));
+
+} /* end of cuddBddTransferRecur */
+
diff --git a/src/bdd/cudd/cuddCache.c b/src/bdd/cudd/cuddCache.c
new file mode 100644
index 00000000..6598948a
--- /dev/null
+++ b/src/bdd/cudd/cuddCache.c
@@ -0,0 +1,1023 @@
+/**CFile***********************************************************************
+
+ FileName [cuddCache.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions for cache insertion and lookup.]
+
+ Description [Internal procedures included in this module:
+ <ul>
+ <li> cuddInitCache()
+ <li> cuddCacheInsert()
+ <li> cuddCacheInsert2()
+ <li> cuddCacheLookup()
+ <li> cuddCacheLookupZdd()
+ <li> cuddCacheLookup2()
+ <li> cuddCacheLookup2Zdd()
+ <li> cuddConstantLookup()
+ <li> cuddCacheProfile()
+ <li> cuddCacheResize()
+ <li> cuddCacheFlush()
+ <li> cuddComputeFloorLog2()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ </ul> ]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifdef DD_CACHE_PROFILE
+#define DD_HYSTO_BINS 8
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddCache.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Initializes the computed table.]
+
+ Description [Initializes the computed table. It is called by
+ Cudd_Init. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Init]
+
+******************************************************************************/
+int
+cuddInitCache(
+ DdManager * unique /* unique table */,
+ unsigned int cacheSize /* initial size of the cache */,
+ unsigned int maxCacheSize /* cache size beyond which no resizing occurs */)
+{
+ int i;
+ unsigned int logSize;
+#ifndef DD_CACHE_PROFILE
+ DdNodePtr *mem;
+ ptruint offset;
+#endif
+
+ /* Round cacheSize to largest power of 2 not greater than the requested
+ ** initial cache size. */
+ logSize = cuddComputeFloorLog2(ddMax(cacheSize,unique->slots/2));
+ cacheSize = 1 << logSize;
+ unique->acache = ALLOC(DdCache,cacheSize+1);
+ if (unique->acache == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ /* If the size of the cache entry is a power of 2, we want to
+ ** enforce alignment to that power of two. This happens when
+ ** DD_CACHE_PROFILE is not defined. */
+#ifdef DD_CACHE_PROFILE
+ unique->cache = unique->acache;
+ unique->memused += (cacheSize) * sizeof(DdCache);
+#else
+ mem = (DdNodePtr *) unique->acache;
+ offset = (ptruint) mem & (sizeof(DdCache) - 1);
+ mem += (sizeof(DdCache) - offset) / sizeof(DdNodePtr);
+ unique->cache = (DdCache *) mem;
+ assert(((ptruint) unique->cache & (sizeof(DdCache) - 1)) == 0);
+ unique->memused += (cacheSize+1) * sizeof(DdCache);
+#endif
+ unique->cacheSlots = cacheSize;
+ unique->cacheShift = sizeof(int) * 8 - logSize;
+ unique->maxCacheHard = maxCacheSize;
+ /* If cacheSlack is non-negative, we can resize. */
+ unique->cacheSlack = (int) ddMin(maxCacheSize,
+ DD_MAX_CACHE_TO_SLOTS_RATIO*unique->slots) -
+ 2 * (int) cacheSize;
+ Cudd_SetMinHit(unique,DD_MIN_HIT);
+ /* Initialize to avoid division by 0 and immediate resizing. */
+ unique->cacheMisses = (double) (int) (cacheSize * unique->minHit + 1);
+ unique->cacheHits = 0;
+ unique->totCachehits = 0;
+ /* The sum of cacheMisses and totCacheMisses is always correct,
+ ** even though cacheMisses is larger than it should for the reasons
+ ** explained above. */
+ unique->totCacheMisses = -unique->cacheMisses;
+ unique->cachecollisions = 0;
+ unique->cacheinserts = 0;
+ unique->cacheLastInserts = 0;
+ unique->cachedeletions = 0;
+
+ /* Initialize the cache */
+ for (i = 0; (unsigned) i < cacheSize; i++) {
+ unique->cache[i].h = 0; /* unused slots */
+ unique->cache[i].data = NULL; /* invalid entry */
+#ifdef DD_CACHE_PROFILE
+ unique->cache[i].count = 0;
+#endif
+ }
+
+ return(1);
+
+} /* end of cuddInitCache */
+
+
+/**Function********************************************************************
+
+ Synopsis [Inserts a result in the cache.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [cuddCacheInsert2 cuddCacheInsert1]
+
+******************************************************************************/
+void
+cuddCacheInsert(
+ DdManager * table,
+ ptruint op,
+ DdNode * f,
+ DdNode * g,
+ DdNode * h,
+ DdNode * data)
+{
+ int posn;
+ register DdCache *entry;
+ ptruint uf, ug, uh;
+
+ uf = (ptruint) f | (op & 0xe);
+ ug = (ptruint) g | (op >> 4);
+ uh = (ptruint) h;
+
+ posn = ddCHash2(uh,uf,ug,table->cacheShift);
+ entry = &table->cache[posn];
+
+ table->cachecollisions += entry->data != NULL;
+ table->cacheinserts++;
+
+ entry->f = (DdNode *) uf;
+ entry->g = (DdNode *) ug;
+ entry->h = uh;
+ entry->data = data;
+#ifdef DD_CACHE_PROFILE
+ entry->count++;
+#endif
+
+} /* end of cuddCacheInsert */
+
+
+/**Function********************************************************************
+
+ Synopsis [Inserts a result in the cache for a function with two
+ operands.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [cuddCacheInsert cuddCacheInsert1]
+
+******************************************************************************/
+void
+cuddCacheInsert2(
+ DdManager * table,
+ DdNode * (*op)(DdManager *, DdNode *, DdNode *),
+ DdNode * f,
+ DdNode * g,
+ DdNode * data)
+{
+ int posn;
+ register DdCache *entry;
+
+ posn = ddCHash2(op,f,g,table->cacheShift);
+ entry = &table->cache[posn];
+
+ if (entry->data != NULL) {
+ table->cachecollisions++;
+ }
+ table->cacheinserts++;
+
+ entry->f = f;
+ entry->g = g;
+ entry->h = (ptruint) op;
+ entry->data = data;
+#ifdef DD_CACHE_PROFILE
+ entry->count++;
+#endif
+
+} /* end of cuddCacheInsert2 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Inserts a result in the cache for a function with two
+ operands.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [cuddCacheInsert cuddCacheInsert2]
+
+******************************************************************************/
+void
+cuddCacheInsert1(
+ DdManager * table,
+ DdNode * (*op)(DdManager *, DdNode *),
+ DdNode * f,
+ DdNode * data)
+{
+ int posn;
+ register DdCache *entry;
+
+ posn = ddCHash2(op,f,f,table->cacheShift);
+ entry = &table->cache[posn];
+
+ if (entry->data != NULL) {
+ table->cachecollisions++;
+ }
+ table->cacheinserts++;
+
+ entry->f = f;
+ entry->g = f;
+ entry->h = (ptruint) op;
+ entry->data = data;
+#ifdef DD_CACHE_PROFILE
+ entry->count++;
+#endif
+
+} /* end of cuddCacheInsert1 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Looks up in the cache for the result of op applied to f,
+ g, and h.]
+
+ Description [Returns the result if found; it returns NULL if no
+ result is found.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddCacheLookup2 cuddCacheLookup1]
+
+******************************************************************************/
+DdNode *
+cuddCacheLookup(
+ DdManager * table,
+ ptruint op,
+ DdNode * f,
+ DdNode * g,
+ DdNode * h)
+{
+ int posn;
+ DdCache *en,*cache;
+ DdNode *data;
+ ptruint uf, ug, uh;
+
+ uf = (ptruint) f | (op & 0xe);
+ ug = (ptruint) g | (op >> 4);
+ uh = (ptruint) h;
+
+ cache = table->cache;
+#ifdef DD_DEBUG
+ if (cache == NULL) {
+ return(NULL);
+ }
+#endif
+
+ posn = ddCHash2(uh,uf,ug,table->cacheShift);
+ en = &cache[posn];
+ if (en->data != NULL && en->f==(DdNodePtr)uf && en->g==(DdNodePtr)ug &&
+ en->h==uh) {
+ data = Cudd_Regular(en->data);
+ table->cacheHits++;
+ if (data->ref == 0) {
+ cuddReclaim(table,data);
+ }
+ return(en->data);
+ }
+
+ /* Cache miss: decide whether to resize. */
+ table->cacheMisses++;
+
+ if (table->cacheSlack >= 0 &&
+ table->cacheHits > table->cacheMisses * table->minHit) {
+ cuddCacheResize(table);
+ }
+
+ return(NULL);
+
+} /* end of cuddCacheLookup */
+
+
+/**Function********************************************************************
+
+ Synopsis [Looks up in the cache for the result of op applied to f,
+ g, and h.]
+
+ Description [Returns the result if found; it returns NULL if no
+ result is found.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddCacheLookup2Zdd cuddCacheLookup1Zdd]
+
+******************************************************************************/
+DdNode *
+cuddCacheLookupZdd(
+ DdManager * table,
+ ptruint op,
+ DdNode * f,
+ DdNode * g,
+ DdNode * h)
+{
+ int posn;
+ DdCache *en,*cache;
+ DdNode *data;
+ ptruint uf, ug, uh;
+
+ uf = (ptruint) f | (op & 0xe);
+ ug = (ptruint) g | (op >> 4);
+ uh = (ptruint) h;
+
+ cache = table->cache;
+#ifdef DD_DEBUG
+ if (cache == NULL) {
+ return(NULL);
+ }
+#endif
+
+ posn = ddCHash2(uh,uf,ug,table->cacheShift);
+ en = &cache[posn];
+ if (en->data != NULL && en->f==(DdNodePtr)uf && en->g==(DdNodePtr)ug &&
+ en->h==uh) {
+ data = Cudd_Regular(en->data);
+ table->cacheHits++;
+ if (data->ref == 0) {
+ cuddReclaimZdd(table,data);
+ }
+ return(en->data);
+ }
+
+ /* Cache miss: decide whether to resize. */
+ table->cacheMisses++;
+
+ if (table->cacheSlack >= 0 &&
+ table->cacheHits > table->cacheMisses * table->minHit) {
+ cuddCacheResize(table);
+ }
+
+ return(NULL);
+
+} /* end of cuddCacheLookupZdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Looks up in the cache for the result of op applied to f
+ and g.]
+
+ Description [Returns the result if found; it returns NULL if no
+ result is found.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddCacheLookup cuddCacheLookup1]
+
+******************************************************************************/
+DdNode *
+cuddCacheLookup2(
+ DdManager * table,
+ DdNode * (*op)(DdManager *, DdNode *, DdNode *),
+ DdNode * f,
+ DdNode * g)
+{
+ int posn;
+ DdCache *en,*cache;
+ DdNode *data;
+
+ cache = table->cache;
+#ifdef DD_DEBUG
+ if (cache == NULL) {
+ return(NULL);
+ }
+#endif
+
+ posn = ddCHash2(op,f,g,table->cacheShift);
+ en = &cache[posn];
+ if (en->data != NULL && en->f==f && en->g==g && en->h==(ptruint)op) {
+ data = Cudd_Regular(en->data);
+ table->cacheHits++;
+ if (data->ref == 0) {
+ cuddReclaim(table,data);
+ }
+ return(en->data);
+ }
+
+ /* Cache miss: decide whether to resize. */
+ table->cacheMisses++;
+
+ if (table->cacheSlack >= 0 &&
+ table->cacheHits > table->cacheMisses * table->minHit) {
+ cuddCacheResize(table);
+ }
+
+ return(NULL);
+
+} /* end of cuddCacheLookup2 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Looks up in the cache for the result of op applied to f.]
+
+ Description [Returns the result if found; it returns NULL if no
+ result is found.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddCacheLookup cuddCacheLookup2]
+
+******************************************************************************/
+DdNode *
+cuddCacheLookup1(
+ DdManager * table,
+ DdNode * (*op)(DdManager *, DdNode *),
+ DdNode * f)
+{
+ int posn;
+ DdCache *en,*cache;
+ DdNode *data;
+
+ cache = table->cache;
+#ifdef DD_DEBUG
+ if (cache == NULL) {
+ return(NULL);
+ }
+#endif
+
+ posn = ddCHash2(op,f,f,table->cacheShift);
+ en = &cache[posn];
+ if (en->data != NULL && en->f==f && en->h==(ptruint)op) {
+ data = Cudd_Regular(en->data);
+ table->cacheHits++;
+ if (data->ref == 0) {
+ cuddReclaim(table,data);
+ }
+ return(en->data);
+ }
+
+ /* Cache miss: decide whether to resize. */
+ table->cacheMisses++;
+
+ if (table->cacheSlack >= 0 &&
+ table->cacheHits > table->cacheMisses * table->minHit) {
+ cuddCacheResize(table);
+ }
+
+ return(NULL);
+
+} /* end of cuddCacheLookup1 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Looks up in the cache for the result of op applied to f
+ and g.]
+
+ Description [Returns the result if found; it returns NULL if no
+ result is found.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddCacheLookupZdd cuddCacheLookup1Zdd]
+
+******************************************************************************/
+DdNode *
+cuddCacheLookup2Zdd(
+ DdManager * table,
+ DdNode * (*op)(DdManager *, DdNode *, DdNode *),
+ DdNode * f,
+ DdNode * g)
+{
+ int posn;
+ DdCache *en,*cache;
+ DdNode *data;
+
+ cache = table->cache;
+#ifdef DD_DEBUG
+ if (cache == NULL) {
+ return(NULL);
+ }
+#endif
+
+ posn = ddCHash2(op,f,g,table->cacheShift);
+ en = &cache[posn];
+ if (en->data != NULL && en->f==f && en->g==g && en->h==(ptruint)op) {
+ data = Cudd_Regular(en->data);
+ table->cacheHits++;
+ if (data->ref == 0) {
+ cuddReclaimZdd(table,data);
+ }
+ return(en->data);
+ }
+
+ /* Cache miss: decide whether to resize. */
+ table->cacheMisses++;
+
+ if (table->cacheSlack >= 0 &&
+ table->cacheHits > table->cacheMisses * table->minHit) {
+ cuddCacheResize(table);
+ }
+
+ return(NULL);
+
+} /* end of cuddCacheLookup2Zdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Looks up in the cache for the result of op applied to f.]
+
+ Description [Returns the result if found; it returns NULL if no
+ result is found.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddCacheLookupZdd cuddCacheLookup2Zdd]
+
+******************************************************************************/
+DdNode *
+cuddCacheLookup1Zdd(
+ DdManager * table,
+ DdNode * (*op)(DdManager *, DdNode *),
+ DdNode * f)
+{
+ int posn;
+ DdCache *en,*cache;
+ DdNode *data;
+
+ cache = table->cache;
+#ifdef DD_DEBUG
+ if (cache == NULL) {
+ return(NULL);
+ }
+#endif
+
+ posn = ddCHash2(op,f,f,table->cacheShift);
+ en = &cache[posn];
+ if (en->data != NULL && en->f==f && en->h==(ptruint)op) {
+ data = Cudd_Regular(en->data);
+ table->cacheHits++;
+ if (data->ref == 0) {
+ cuddReclaimZdd(table,data);
+ }
+ return(en->data);
+ }
+
+ /* Cache miss: decide whether to resize. */
+ table->cacheMisses++;
+
+ if (table->cacheSlack >= 0 &&
+ table->cacheHits > table->cacheMisses * table->minHit) {
+ cuddCacheResize(table);
+ }
+
+ return(NULL);
+
+} /* end of cuddCacheLookup1Zdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Looks up in the cache for the result of op applied to f,
+ g, and h.]
+
+ Description [Looks up in the cache for the result of op applied to f,
+ g, and h. Assumes that the calling procedure (e.g.,
+ Cudd_bddIteConstant) is only interested in whether the result is
+ constant or not. Returns the result if found (possibly
+ DD_NON_CONSTANT); otherwise it returns NULL.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddCacheLookup]
+
+******************************************************************************/
+DdNode *
+cuddConstantLookup(
+ DdManager * table,
+ ptruint op,
+ DdNode * f,
+ DdNode * g,
+ DdNode * h)
+{
+ int posn;
+ DdCache *en,*cache;
+ ptruint uf, ug, uh;
+
+ uf = (ptruint) f | (op & 0xe);
+ ug = (ptruint) g | (op >> 4);
+ uh = (ptruint) h;
+
+ cache = table->cache;
+#ifdef DD_DEBUG
+ if (cache == NULL) {
+ return(NULL);
+ }
+#endif
+ posn = ddCHash2(uh,uf,ug,table->cacheShift);
+ en = &cache[posn];
+
+ /* We do not reclaim here because the result should not be
+ * referenced, but only tested for being a constant.
+ */
+ if (en->data != NULL &&
+ en->f == (DdNodePtr)uf && en->g == (DdNodePtr)ug && en->h == uh) {
+ table->cacheHits++;
+ return(en->data);
+ }
+
+ /* Cache miss: decide whether to resize. */
+ table->cacheMisses++;
+
+ if (table->cacheSlack >= 0 &&
+ table->cacheHits > table->cacheMisses * table->minHit) {
+ cuddCacheResize(table);
+ }
+
+ return(NULL);
+
+} /* end of cuddConstantLookup */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes and prints a profile of the cache usage.]
+
+ Description [Computes and prints a profile of the cache usage.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddCacheProfile(
+ DdManager * table,
+ FILE * fp)
+{
+ DdCache *cache = table->cache;
+ int slots = table->cacheSlots;
+ int nzeroes = 0;
+ int i, retval;
+ double exUsed;
+
+#ifdef DD_CACHE_PROFILE
+ double count, mean, meansq, stddev, expected;
+ long max, min;
+ int imax, imin;
+ double *hystogramQ, *hystogramR; /* histograms by quotient and remainder */
+ int nbins = DD_HYSTO_BINS;
+ int bin;
+ long thiscount;
+ double totalcount, exStddev;
+
+ meansq = mean = expected = 0.0;
+ max = min = (long) cache[0].count;
+ imax = imin = 0;
+ totalcount = 0.0;
+
+ hystogramQ = ALLOC(double, nbins);
+ if (hystogramQ == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ hystogramR = ALLOC(double, nbins);
+ if (hystogramR == NULL) {
+ FREE(hystogramQ);
+ table->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (i = 0; i < nbins; i++) {
+ hystogramQ[i] = 0;
+ hystogramR[i] = 0;
+ }
+
+ for (i = 0; i < slots; i++) {
+ thiscount = (long) cache[i].count;
+ if (thiscount > max) {
+ max = thiscount;
+ imax = i;
+ }
+ if (thiscount < min) {
+ min = thiscount;
+ imin = i;
+ }
+ if (thiscount == 0) {
+ nzeroes++;
+ }
+ count = (double) thiscount;
+ mean += count;
+ meansq += count * count;
+ totalcount += count;
+ expected += count * (double) i;
+ bin = (i * nbins) / slots;
+ hystogramQ[bin] += (double) thiscount;
+ bin = i % nbins;
+ hystogramR[bin] += (double) thiscount;
+ }
+ mean /= (double) slots;
+ meansq /= (double) slots;
+
+ /* Compute the standard deviation from both the data and the
+ ** theoretical model for a random distribution. */
+ stddev = sqrt(meansq - mean*mean);
+ exStddev = sqrt((1 - 1/(double) slots) * totalcount / (double) slots);
+
+ retval = fprintf(fp,"Cache average accesses = %g\n", mean);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Cache access standard deviation = %g ", stddev);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"(expected = %g)\n", exStddev);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Cache max accesses = %ld for slot %d\n", max, imax);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Cache min accesses = %ld for slot %d\n", min, imin);
+ if (retval == EOF) return(0);
+ exUsed = 100.0 * (1.0 - exp(-totalcount / (double) slots));
+ retval = fprintf(fp,"Cache used slots = %.2f%% (expected %.2f%%)\n",
+ 100.0 - (double) nzeroes * 100.0 / (double) slots,
+ exUsed);
+ if (retval == EOF) return(0);
+
+ if (totalcount > 0) {
+ expected /= totalcount;
+ retval = fprintf(fp,"Cache access hystogram for %d bins", nbins);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp," (expected bin value = %g)\nBy quotient:",
+ expected);
+ if (retval == EOF) return(0);
+ for (i = nbins - 1; i>=0; i--) {
+ retval = fprintf(fp," %.0f", hystogramQ[i]);
+ if (retval == EOF) return(0);
+ }
+ retval = fprintf(fp,"\nBy residue: ");
+ if (retval == EOF) return(0);
+ for (i = nbins - 1; i>=0; i--) {
+ retval = fprintf(fp," %.0f", hystogramR[i]);
+ if (retval == EOF) return(0);
+ }
+ retval = fprintf(fp,"\n");
+ if (retval == EOF) return(0);
+ }
+
+ FREE(hystogramQ);
+ FREE(hystogramR);
+#else
+ for (i = 0; i < slots; i++) {
+ nzeroes += cache[i].h == 0;
+ }
+ exUsed = 100.0 *
+ (1.0 - exp(-(table->cacheinserts - table->cacheLastInserts) /
+ (double) slots));
+ retval = fprintf(fp,"Cache used slots = %.2f%% (expected %.2f%%)\n",
+ 100.0 - (double) nzeroes * 100.0 / (double) slots,
+ exUsed);
+ if (retval == EOF) return(0);
+#endif
+ return(1);
+
+} /* end of cuddCacheProfile */
+
+
+/**Function********************************************************************
+
+ Synopsis [Resizes the cache.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+cuddCacheResize(
+ DdManager * table)
+{
+ DdCache *cache, *oldcache, *oldacache, *entry, *old;
+ int i;
+ int posn, shift;
+ unsigned int slots, oldslots;
+ double offset;
+ int moved = 0;
+ extern void (*MMoutOfMemory)(long);
+ void (*saveHandler)(long);
+#ifndef DD_CACHE_PROFILE
+ ptruint misalignment;
+ DdNodePtr *mem;
+#endif
+
+ oldcache = table->cache;
+ oldacache = table->acache;
+ oldslots = table->cacheSlots;
+ slots = table->cacheSlots = oldslots << 1;
+
+#ifdef DD_VERBOSE
+ (void) fprintf(table->err,"Resizing the cache from %d to %d entries\n",
+ oldslots, slots);
+ (void) fprintf(table->err,
+ "\thits = %g\tmisses = %g\thit ratio = %5.3f\n",
+ table->cacheHits, table->cacheMisses,
+ table->cacheHits / (table->cacheHits + table->cacheMisses));
+#endif
+
+ saveHandler = MMoutOfMemory;
+ MMoutOfMemory = Cudd_OutOfMem;
+ table->acache = cache = ALLOC(DdCache,slots+1);
+ MMoutOfMemory = saveHandler;
+ /* If we fail to allocate the new table we just give up. */
+ if (cache == NULL) {
+#ifdef DD_VERBOSE
+ (void) fprintf(table->err,"Resizing failed. Giving up.\n");
+#endif
+ table->cacheSlots = oldslots;
+ table->acache = oldacache;
+ /* Do not try to resize again. */
+ table->maxCacheHard = oldslots - 1;
+ table->cacheSlack = - (oldslots + 1);
+ return;
+ }
+ /* If the size of the cache entry is a power of 2, we want to
+ ** enforce alignment to that power of two. This happens when
+ ** DD_CACHE_PROFILE is not defined. */
+#ifdef DD_CACHE_PROFILE
+ table->cache = cache;
+#else
+ mem = (DdNodePtr *) cache;
+ misalignment = (ptruint) mem & (sizeof(DdCache) - 1);
+ mem += (sizeof(DdCache) - misalignment) / sizeof(DdNodePtr);
+ table->cache = cache = (DdCache *) mem;
+ assert(((ptruint) table->cache & (sizeof(DdCache) - 1)) == 0);
+#endif
+ shift = --(table->cacheShift);
+ table->memused += (slots - oldslots) * sizeof(DdCache);
+ table->cacheSlack -= slots; /* need these many slots to double again */
+
+ /* Clear new cache. */
+ for (i = 0; (unsigned) i < slots; i++) {
+ cache[i].data = NULL;
+ cache[i].h = 0;
+#ifdef DD_CACHE_PROFILE
+ cache[i].count = 0;
+#endif
+ }
+
+ /* Copy from old cache to new one. */
+ for (i = 0; (unsigned) i < oldslots; i++) {
+ old = &oldcache[i];
+ if (old->data != NULL) {
+ posn = ddCHash2(old->h,old->f,old->g,shift);
+ entry = &cache[posn];
+ entry->f = old->f;
+ entry->g = old->g;
+ entry->h = old->h;
+ entry->data = old->data;
+#ifdef DD_CACHE_PROFILE
+ entry->count = 1;
+#endif
+ moved++;
+ }
+ }
+
+ FREE(oldacache);
+
+ /* Reinitialize measurements so as to avoid division by 0 and
+ ** immediate resizing.
+ */
+ offset = (double) (int) (slots * table->minHit + 1);
+ table->totCacheMisses += table->cacheMisses - offset;
+ table->cacheMisses = offset;
+ table->totCachehits += table->cacheHits;
+ table->cacheHits = 0;
+ table->cacheLastInserts = table->cacheinserts - (double) moved;
+
+} /* end of cuddCacheResize */
+
+
+/**Function********************************************************************
+
+ Synopsis [Flushes the cache.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+cuddCacheFlush(
+ DdManager * table)
+{
+ int i, slots;
+ DdCache *cache;
+
+ slots = table->cacheSlots;
+ cache = table->cache;
+ for (i = 0; i < slots; i++) {
+ table->cachedeletions += cache[i].data != NULL;
+ cache[i].data = NULL;
+ }
+ table->cacheLastInserts = table->cacheinserts;
+
+ return;
+
+} /* end of cuddCacheFlush */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the floor of the logarithm to the base 2.]
+
+ Description [Returns the floor of the logarithm to the base 2.
+ The input value is assumed to be greater than 0.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddComputeFloorLog2(
+ unsigned int value)
+{
+ int floorLog = 0;
+#ifdef DD_DEBUG
+ assert(value > 0);
+#endif
+ while (value > 1) {
+ floorLog++;
+ value >>= 1;
+ }
+ return(floorLog);
+
+} /* end of cuddComputeFloorLog2 */
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
diff --git a/src/bdd/cudd/cuddCheck.c b/src/bdd/cudd/cuddCheck.c
new file mode 100644
index 00000000..3db08dd6
--- /dev/null
+++ b/src/bdd/cudd/cuddCheck.c
@@ -0,0 +1,851 @@
+/**CFile***********************************************************************
+
+ FileName [cuddCheck.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions to check consistency of data structures.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_DebugCheck()
+ <li> Cudd_CheckKeys()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddHeapProfile()
+ <li> cuddPrintNode()
+ <li> cuddPrintVarGroups()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> debugFindParent()
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddCheck.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static void debugFindParent ARGS((DdManager *table, DdNode *node));
+#if 0
+static void debugCheckParent ARGS((DdManager *table, DdNode *node));
+#endif
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks for inconsistencies in the DD heap.]
+
+ Description [Checks for inconsistencies in the DD heap:
+ <ul>
+ <li> node has illegal index
+ <li> live node has dead children
+ <li> node has illegal Then or Else pointers
+ <li> BDD/ADD node has identical children
+ <li> ZDD node has zero then child
+ <li> wrong number of total nodes
+ <li> wrong number of dead nodes
+ <li> ref count error at node
+ </ul>
+ Returns 0 if no inconsistencies are found; DD_OUT_OF_MEM if there is
+ not enough memory; 1 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_CheckKeys]
+
+******************************************************************************/
+int
+Cudd_DebugCheck(
+ DdManager * table)
+{
+ unsigned int i;
+ int j,count;
+ int slots;
+ DdNodePtr *nodelist;
+ DdNode *f;
+ DdNode *sentinel = &(table->sentinel);
+ st_table *edgeTable; /* stores internal ref count for each node */
+ st_generator *gen;
+ int flag = 0;
+ int totalNode;
+ int deadNode;
+ int index;
+
+
+ edgeTable = st_init_table(st_ptrcmp,st_ptrhash);
+ if (edgeTable == NULL) return(CUDD_OUT_OF_MEM);
+
+ /* Check the BDD/ADD subtables. */
+ for (i = 0; i < (unsigned) table->size; i++) {
+ index = table->invperm[i];
+ if (i != (unsigned) table->perm[index]) {
+ (void) fprintf(table->err,
+ "Permutation corrupted: invperm[%d] = %d\t perm[%d] = %d\n",
+ i, index, index, table->perm[index]);
+ }
+ nodelist = table->subtables[i].nodelist;
+ slots = table->subtables[i].slots;
+
+ totalNode = 0;
+ deadNode = 0;
+ for (j = 0; j < slots; j++) { /* for each subtable slot */
+ f = nodelist[j];
+ while (f != sentinel) {
+ totalNode++;
+ if (cuddT(f) != NULL && cuddE(f) != NULL && f->ref != 0) {
+ if ((int) f->index != index) {
+ (void) fprintf(table->err,
+ "Error: node has illegal index\n");
+ cuddPrintNode(f,table->err);
+ flag = 1;
+ }
+ if ((unsigned) cuddI(table,cuddT(f)->index) <= i ||
+ (unsigned) cuddI(table,Cudd_Regular(cuddE(f))->index)
+ <= i) {
+ (void) fprintf(table->err,
+ "Error: node has illegal children\n");
+ cuddPrintNode(f,table->err);
+ flag = 1;
+ }
+ if (Cudd_Regular(cuddT(f)) != cuddT(f)) {
+ (void) fprintf(table->err,
+ "Error: node has illegal form\n");
+ cuddPrintNode(f,table->err);
+ flag = 1;
+ }
+ if (cuddT(f) == cuddE(f)) {
+ (void) fprintf(table->err,
+ "Error: node has identical children\n");
+ cuddPrintNode(f,table->err);
+ flag = 1;
+ }
+ if (cuddT(f)->ref == 0 || Cudd_Regular(cuddE(f))->ref == 0) {
+ (void) fprintf(table->err,
+ "Error: live node has dead children\n");
+ cuddPrintNode(f,table->err);
+ flag =1;
+ }
+ /* Increment the internal reference count for the
+ ** then child of the current node.
+ */
+ if (st_lookup(edgeTable,(char *)cuddT(f),(char **)&count)) {
+ count++;
+ } else {
+ count = 1;
+ }
+ if (st_insert(edgeTable,(char *)cuddT(f),
+ (char *)(long)count) == ST_OUT_OF_MEM) {
+ st_free_table(edgeTable);
+ return(CUDD_OUT_OF_MEM);
+ }
+
+ /* Increment the internal reference count for the
+ ** else child of the current node.
+ */
+ if (st_lookup(edgeTable,(char *)Cudd_Regular(cuddE(f)),(char **)&count)) {
+ count++;
+ } else {
+ count = 1;
+ }
+ if (st_insert(edgeTable,(char *)Cudd_Regular(cuddE(f)),
+ (char *)(long)count) == ST_OUT_OF_MEM) {
+ st_free_table(edgeTable);
+ return(CUDD_OUT_OF_MEM);
+ }
+ } else if (cuddT(f) != NULL && cuddE(f) != NULL && f->ref == 0) {
+ deadNode++;
+#if 0
+ debugCheckParent(table,f);
+#endif
+ } else {
+ fprintf(table->err,
+ "Error: node has illegal Then or Else pointers\n");
+ cuddPrintNode(f,table->err);
+ flag = 1;
+ }
+
+ f = f->next;
+ } /* for each element of the collision list */
+ } /* for each subtable slot */
+
+ if ((unsigned) totalNode != table->subtables[i].keys) {
+ fprintf(table->err,"Error: wrong number of total nodes\n");
+ flag = 1;
+ }
+ if ((unsigned) deadNode != table->subtables[i].dead) {
+ fprintf(table->err,"Error: wrong number of dead nodes\n");
+ flag = 1;
+ }
+ } /* for each BDD/ADD subtable */
+
+ /* Check the ZDD subtables. */
+ for (i = 0; i < (unsigned) table->sizeZ; i++) {
+ index = table->invpermZ[i];
+ if (i != (unsigned) table->permZ[index]) {
+ (void) fprintf(table->err,
+ "Permutation corrupted: invpermZ[%d] = %d\t permZ[%d] = %d in ZDD\n",
+ i, index, index, table->permZ[index]);
+ }
+ nodelist = table->subtableZ[i].nodelist;
+ slots = table->subtableZ[i].slots;
+
+ totalNode = 0;
+ deadNode = 0;
+ for (j = 0; j < slots; j++) { /* for each subtable slot */
+ f = nodelist[j];
+ while (f != NULL) {
+ totalNode++;
+ if (cuddT(f) != NULL && cuddE(f) != NULL && f->ref != 0) {
+ if ((int) f->index != index) {
+ (void) fprintf(table->err,
+ "Error: ZDD node has illegal index\n");
+ cuddPrintNode(f,table->err);
+ flag = 1;
+ }
+ if (Cudd_IsComplement(cuddT(f)) ||
+ Cudd_IsComplement(cuddE(f))) {
+ (void) fprintf(table->err,
+ "Error: ZDD node has complemented children\n");
+ cuddPrintNode(f,table->err);
+ flag = 1;
+ }
+ if ((unsigned) cuddIZ(table,cuddT(f)->index) <= i ||
+ (unsigned) cuddIZ(table,cuddE(f)->index) <= i) {
+ (void) fprintf(table->err,
+ "Error: ZDD node has illegal children\n");
+ cuddPrintNode(f,table->err);
+ cuddPrintNode(cuddT(f),table->err);
+ cuddPrintNode(cuddE(f),table->err);
+ flag = 1;
+ }
+ if (cuddT(f) == DD_ZERO(table)) {
+ (void) fprintf(table->err,
+ "Error: ZDD node has zero then child\n");
+ cuddPrintNode(f,table->err);
+ flag = 1;
+ }
+ if (cuddT(f)->ref == 0 || cuddE(f)->ref == 0) {
+ (void) fprintf(table->err,
+ "Error: ZDD live node has dead children\n");
+ cuddPrintNode(f,table->err);
+ flag =1;
+ }
+ /* Increment the internal reference count for the
+ ** then child of the current node.
+ */
+ if (st_lookup(edgeTable,(char *)cuddT(f),(char **)&count)) {
+ count++;
+ } else {
+ count = 1;
+ }
+ if (st_insert(edgeTable,(char *)cuddT(f),
+ (char *)(long)count) == ST_OUT_OF_MEM) {
+ st_free_table(edgeTable);
+ return(CUDD_OUT_OF_MEM);
+ }
+
+ /* Increment the internal reference count for the
+ ** else child of the current node.
+ */
+ if (st_lookup(edgeTable,(char *)cuddE(f),(char **)&count)) {
+ count++;
+ } else {
+ count = 1;
+ }
+ if (st_insert(edgeTable,(char *)cuddE(f),
+ (char *)(long)count) == ST_OUT_OF_MEM) {
+ st_free_table(edgeTable);
+ table->errorCode = CUDD_MEMORY_OUT;
+ return(CUDD_OUT_OF_MEM);
+ }
+ } else if (cuddT(f) != NULL && cuddE(f) != NULL && f->ref == 0) {
+ deadNode++;
+#if 0
+ debugCheckParent(table,f);
+#endif
+ } else {
+ fprintf(table->err,
+ "Error: ZDD node has illegal Then or Else pointers\n");
+ cuddPrintNode(f,table->err);
+ flag = 1;
+ }
+
+ f = f->next;
+ } /* for each element of the collision list */
+ } /* for each subtable slot */
+
+ if ((unsigned) totalNode != table->subtableZ[i].keys) {
+ fprintf(table->err,
+ "Error: wrong number of total nodes in ZDD\n");
+ flag = 1;
+ }
+ if ((unsigned) deadNode != table->subtableZ[i].dead) {
+ fprintf(table->err,
+ "Error: wrong number of dead nodes in ZDD\n");
+ flag = 1;
+ }
+ } /* for each ZDD subtable */
+
+ /* Check the constant table. */
+ nodelist = table->constants.nodelist;
+ slots = table->constants.slots;
+
+ totalNode = 0;
+ deadNode = 0;
+ for (j = 0; j < slots; j++) {
+ f = nodelist[j];
+ while (f != NULL) {
+ totalNode++;
+ if (f->ref != 0) {
+ if (f->index != CUDD_CONST_INDEX) {
+ fprintf(table->err,"Error: node has illegal index\n");
+#if SIZEOF_VOID_P == 8
+ fprintf(table->err,
+ " node 0x%lx, id = %d, ref = %d, value = %g\n",
+ (unsigned long)f,f->index,f->ref,cuddV(f));
+#else
+ fprintf(table->err,
+ " node 0x%x, id = %d, ref = %d, value = %g\n",
+ (unsigned)f,f->index,f->ref,cuddV(f));
+#endif
+ flag = 1;
+ }
+ } else {
+ deadNode++;
+ }
+ f = f->next;
+ }
+ }
+ if ((unsigned) totalNode != table->constants.keys) {
+ (void) fprintf(table->err,
+ "Error: wrong number of total nodes in constants\n");
+ flag = 1;
+ }
+ if ((unsigned) deadNode != table->constants.dead) {
+ (void) fprintf(table->err,
+ "Error: wrong number of dead nodes in constants\n");
+ flag = 1;
+ }
+ gen = st_init_gen(edgeTable);
+ while (st_gen(gen,(char **)&f,(char **)&count)) {
+ if (count > (int)(f->ref) && f->ref != DD_MAXREF) {
+#if SIZEOF_VOID_P == 8
+ fprintf(table->err,"ref count error at node 0x%lx, count = %d, id = %d, ref = %d, then = 0x%lx, else = 0x%lx\n",(unsigned long)f,count,f->index,f->ref,(unsigned long)cuddT(f),(unsigned long)cuddE(f));
+#else
+ fprintf(table->err,"ref count error at node 0x%x, count = %d, id = %d, ref = %d, then = 0x%x, else = 0x%x\n",(unsigned)f,count,f->index,f->ref,(unsigned)cuddT(f),(unsigned)cuddE(f));
+#endif
+ debugFindParent(table,f);
+ flag = 1;
+ }
+ }
+ st_free_gen(gen);
+ st_free_table(edgeTable);
+
+ return (flag);
+
+} /* end of Cudd_DebugCheck */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks for several conditions that should not occur.]
+
+ Description [Checks for the following conditions:
+ <ul>
+ <li>Wrong sizes of subtables.
+ <li>Wrong number of keys found in unique subtable.
+ <li>Wrong number of dead found in unique subtable.
+ <li>Wrong number of keys found in the constant table
+ <li>Wrong number of dead found in the constant table
+ <li>Wrong number of total slots found
+ <li>Wrong number of maximum keys found
+ <li>Wrong number of total dead found
+ </ul>
+ Reports the average length of non-empty lists. Returns the number of
+ subtables for which the number of keys is wrong.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DebugCheck]
+
+******************************************************************************/
+int
+Cudd_CheckKeys(
+ DdManager * table)
+{
+ int size;
+ int i,j;
+ DdNodePtr *nodelist;
+ DdNode *node;
+ DdNode *sentinel = &(table->sentinel);
+ DdSubtable *subtable;
+ int keys;
+ int dead;
+ int count = 0;
+ int totalKeys = 0;
+ int totalSlots = 0;
+ int totalDead = 0;
+ int nonEmpty = 0;
+ unsigned int slots;
+ int logSlots;
+ int shift;
+
+ size = table->size;
+
+ for (i = 0; i < size; i++) {
+ subtable = &(table->subtables[i]);
+ nodelist = subtable->nodelist;
+ keys = subtable->keys;
+ dead = subtable->dead;
+ totalKeys += keys;
+ slots = subtable->slots;
+ shift = subtable->shift;
+ logSlots = sizeof(int) * 8 - shift;
+ if (((slots >> logSlots) << logSlots) != slots) {
+ (void) fprintf(table->err,
+ "Unique table %d is not the right power of 2\n", i);
+ (void) fprintf(table->err,
+ " slots = %u shift = %d\n", slots, shift);
+ }
+ totalSlots += slots;
+ totalDead += dead;
+ for (j = 0; (unsigned) j < slots; j++) {
+ node = nodelist[j];
+ if (node != sentinel) {
+ nonEmpty++;
+ }
+ while (node != sentinel) {
+ keys--;
+ if (node->ref == 0) {
+ dead--;
+ }
+ node = node->next;
+ }
+ }
+ if (keys != 0) {
+ (void) fprintf(table->err, "Wrong number of keys found \
+in unique table %d (difference=%d)\n", i, keys);
+ count++;
+ }
+ if (dead != 0) {
+ (void) fprintf(table->err, "Wrong number of dead found \
+in unique table no. %d (difference=%d)\n", i, dead);
+ }
+ } /* for each BDD/ADD subtable */
+
+ /* Check the ZDD subtables. */
+ size = table->sizeZ;
+
+ for (i = 0; i < size; i++) {
+ subtable = &(table->subtableZ[i]);
+ nodelist = subtable->nodelist;
+ keys = subtable->keys;
+ dead = subtable->dead;
+ totalKeys += keys;
+ totalSlots += subtable->slots;
+ totalDead += dead;
+ for (j = 0; (unsigned) j < subtable->slots; j++) {
+ node = nodelist[j];
+ if (node != NULL) {
+ nonEmpty++;
+ }
+ while (node != NULL) {
+ keys--;
+ if (node->ref == 0) {
+ dead--;
+ }
+ node = node->next;
+ }
+ }
+ if (keys != 0) {
+ (void) fprintf(table->err, "Wrong number of keys found \
+in ZDD unique table no. %d (difference=%d)\n", i, keys);
+ count++;
+ }
+ if (dead != 0) {
+ (void) fprintf(table->err, "Wrong number of dead found \
+in ZDD unique table no. %d (difference=%d)\n", i, dead);
+ }
+ } /* for each ZDD subtable */
+
+ /* Check the constant table. */
+ subtable = &(table->constants);
+ nodelist = subtable->nodelist;
+ keys = subtable->keys;
+ dead = subtable->dead;
+ totalKeys += keys;
+ totalSlots += subtable->slots;
+ totalDead += dead;
+ for (j = 0; (unsigned) j < subtable->slots; j++) {
+ node = nodelist[j];
+ if (node != NULL) {
+ nonEmpty++;
+ }
+ while (node != NULL) {
+ keys--;
+ if (node->ref == 0) {
+ dead--;
+ }
+ node = node->next;
+ }
+ }
+ if (keys != 0) {
+ (void) fprintf(table->err, "Wrong number of keys found \
+in the constant table (difference=%d)\n", keys);
+ count++;
+ }
+ if (dead != 0) {
+ (void) fprintf(table->err, "Wrong number of dead found \
+in the constant table (difference=%d)\n", dead);
+ }
+ if ((unsigned) totalKeys != table->keys + table->keysZ) {
+ (void) fprintf(table->err, "Wrong number of total keys found \
+(difference=%d)\n", totalKeys-table->keys);
+ }
+ if ((unsigned) totalSlots != table->slots) {
+ (void) fprintf(table->err, "Wrong number of total slots found \
+(difference=%d)\n", totalSlots-table->slots);
+ }
+ if (table->minDead != (unsigned) (table->gcFrac * table->slots)) {
+ (void) fprintf(table->err, "Wrong number of minimum dead found \
+(%d vs. %d)\n", table->minDead,
+ (unsigned) (table->gcFrac * (double) table->slots));
+ }
+ if ((unsigned) totalDead != table->dead + table->deadZ) {
+ (void) fprintf(table->err, "Wrong number of total dead found \
+(difference=%d)\n", totalDead-table->dead);
+ }
+ (void)printf("Average length of non-empty lists = %g\n",
+ (double) table->keys / (double) nonEmpty);
+
+ return(count);
+
+} /* end of Cudd_CheckKeys */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints information about the heap.]
+
+ Description [Prints to the manager's stdout the number of live nodes for each
+ level of the DD heap that contains at least one live node. It also
+ prints a summary containing:
+ <ul>
+ <li> total number of tables;
+ <li> number of tables with live nodes;
+ <li> table with the largest number of live nodes;
+ <li> number of nodes in that table.
+ </ul>
+ If more than one table contains the maximum number of live nodes,
+ only the one of lowest index is reported. Returns 1 in case of success
+ and 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddHeapProfile(
+ DdManager * dd)
+{
+ int ntables = dd->size;
+ DdSubtable *subtables = dd->subtables;
+ int i, /* loop index */
+ nodes, /* live nodes in i-th layer */
+ retval, /* return value of fprintf */
+ largest = -1, /* index of the table with most live nodes */
+ maxnodes = -1, /* maximum number of live nodes in a table */
+ nonempty = 0; /* number of tables with live nodes */
+
+ /* Print header. */
+#if SIZEOF_VOID_P == 8
+ retval = fprintf(dd->out,"*** DD heap profile for 0x%lx ***\n",
+ (unsigned long) dd);
+#else
+ retval = fprintf(dd->out,"*** DD heap profile for 0x%x ***\n",
+ (unsigned) dd);
+#endif
+ if (retval == EOF) return 0;
+
+ /* Print number of live nodes for each nonempty table. */
+ for (i=0; i<ntables; i++) {
+ nodes = subtables[i].keys - subtables[i].dead;
+ if (nodes) {
+ nonempty++;
+ retval = fprintf(dd->out,"%5d: %5d nodes\n", i, nodes);
+ if (retval == EOF) return 0;
+ if (nodes > maxnodes) {
+ maxnodes = nodes;
+ largest = i;
+ }
+ }
+ }
+
+ nodes = dd->constants.keys - dd->constants.dead;
+ if (nodes) {
+ nonempty++;
+ retval = fprintf(dd->out,"const: %5d nodes\n", nodes);
+ if (retval == EOF) return 0;
+ if (nodes > maxnodes) {
+ maxnodes = nodes;
+ largest = CUDD_CONST_INDEX;
+ }
+ }
+
+ /* Print summary. */
+ retval = fprintf(dd->out,"Summary: %d tables, %d non-empty, largest: %d ",
+ ntables+1, nonempty, largest);
+ if (retval == EOF) return 0;
+ retval = fprintf(dd->out,"(with %d nodes)\n", maxnodes);
+ if (retval == EOF) return 0;
+
+ return(1);
+
+} /* end of cuddHeapProfile */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints out information on a node.]
+
+ Description [Prints out information on a node.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+cuddPrintNode(
+ DdNode * f,
+ FILE *fp)
+{
+ f = Cudd_Regular(f);
+#if SIZEOF_VOID_P == 8
+ (void) fprintf(fp," node 0x%lx, id = %d, ref = %d, then = 0x%lx, else = 0x%lx\n",(unsigned long)f,f->index,f->ref,(unsigned long)cuddT(f),(unsigned long)cuddE(f));
+#else
+ (void) fprintf(fp," node 0x%x, id = %d, ref = %d, then = 0x%x, else = 0x%x\n",(unsigned)f,f->index,f->ref,(unsigned)cuddT(f),(unsigned)cuddE(f));
+#endif
+
+} /* end of cuddPrintNode */
+
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints the variable groups as a parenthesized list.]
+
+ Description [Prints the variable groups as a parenthesized list.
+ For each group the level range that it represents is printed. After
+ each group, the group's flags are printed, preceded by a `|'. For
+ each flag (except MTR_TERMINAL) a character is printed.
+ <ul>
+ <li>F: MTR_FIXED
+ <li>N: MTR_NEWNODE
+ <li>S: MTR_SOFT
+ </ul>
+ The second argument, silent, if different from 0, causes
+ Cudd_PrintVarGroups to only check the syntax of the group tree.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+cuddPrintVarGroups(
+ DdManager * dd /* manager */,
+ MtrNode * root /* root of the group tree */,
+ int zdd /* 0: BDD; 1: ZDD */,
+ int silent /* flag to check tree syntax only */)
+{
+ MtrNode *node;
+ int level;
+
+ assert(root != NULL);
+ assert(root->younger == NULL || root->younger->elder == root);
+ assert(root->elder == NULL || root->elder->younger == root);
+ if (zdd) {
+ level = dd->permZ[root->index];
+ } else {
+ level = dd->perm[root->index];
+ }
+ if (!silent) (void) printf("(%d",level);
+ if (MTR_TEST(root,MTR_TERMINAL) || root->child == NULL) {
+ if (!silent) (void) printf(",");
+ } else {
+ node = root->child;
+ while (node != NULL) {
+ assert(node->low >= root->low && (int) (node->low + node->size) <= (int) (root->low + root->size));
+ assert(node->parent == root);
+ cuddPrintVarGroups(dd,node,zdd,silent);
+ node = node->younger;
+ }
+ }
+ if (!silent) {
+ (void) printf("%d", level + root->size - 1);
+ if (root->flags != MTR_DEFAULT) {
+ (void) printf("|");
+ if (MTR_TEST(root,MTR_FIXED)) (void) printf("F");
+ if (MTR_TEST(root,MTR_NEWNODE)) (void) printf("N");
+ if (MTR_TEST(root,MTR_SOFT)) (void) printf("S");
+ }
+ (void) printf(")");
+ if (root->parent == NULL) (void) printf("\n");
+ }
+ assert((root->flags &~(MTR_TERMINAL | MTR_SOFT | MTR_FIXED | MTR_NEWNODE)) == 0);
+ return;
+
+} /* end of cuddPrintVarGroups */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Searches the subtables above node for its parents.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+debugFindParent(
+ DdManager * table,
+ DdNode * node)
+{
+ int i,j;
+ int slots;
+ DdNodePtr *nodelist;
+ DdNode *f;
+
+ for (i = 0; i < cuddI(table,node->index); i++) {
+ nodelist = table->subtables[i].nodelist;
+ slots = table->subtables[i].slots;
+
+ for (j=0;j<slots;j++) {
+ f = nodelist[j];
+ while (f != NULL) {
+ if (cuddT(f) == node || Cudd_Regular(cuddE(f)) == node) {
+#if SIZEOF_VOID_P == 8
+ (void) fprintf(table->out,"parent is at 0x%lx, id = %d, ref = %d, then = 0x%lx, else = 0x%lx\n",
+ (unsigned long)f,f->index,f->ref,(unsigned long)cuddT(f),(unsigned long)cuddE(f));
+#else
+ (void) fprintf(table->out,"parent is at 0x%x, id = %d, ref = %d, then = 0x%x, else = 0x%x\n",
+ (unsigned)f,f->index,f->ref,(unsigned)cuddT(f),(unsigned)cuddE(f));
+#endif
+ }
+ f = f->next;
+ }
+ }
+ }
+
+} /* end of debugFindParent */
+
+
+#if 0
+/**Function********************************************************************
+
+ Synopsis [Reports an error if a (dead) node has a non-dead parent.]
+
+ Description [Searches all the subtables above node. Very expensive.
+ The same check is now implemented more efficiently in ddDebugCheck.]
+
+ SideEffects [None]
+
+ SeeAlso [debugFindParent]
+
+******************************************************************************/
+static void
+debugCheckParent(
+ DdManager * table,
+ DdNode * node)
+{
+ int i,j;
+ int slots;
+ DdNode **nodelist,*f;
+
+ for (i = 0; i < cuddI(table,node->index); i++) {
+ nodelist = table->subtables[i].nodelist;
+ slots = table->subtables[i].slots;
+
+ for (j=0;j<slots;j++) {
+ f = nodelist[j];
+ while (f != NULL) {
+ if ((Cudd_Regular(cuddE(f)) == node || cuddT(f) == node) && f->ref != 0) {
+ (void) fprintf(table->err,
+ "error with zero ref count\n");
+ (void) fprintf(table->err,"parent is 0x%x, id = %d, ref = %d, then = 0x%x, else = 0x%x\n",f,f->index,f->ref,cuddT(f),cuddE(f));
+ (void) fprintf(table->err,"child is 0x%x, id = %d, ref = %d, then = 0x%x, else = 0x%x\n",node,node->index,node->ref,cuddT(node),cuddE(node));
+ }
+ f = f->next;
+ }
+ }
+ }
+}
+#endif
diff --git a/src/bdd/cudd/cuddClip.c b/src/bdd/cudd/cuddClip.c
new file mode 100644
index 00000000..3c728a56
--- /dev/null
+++ b/src/bdd/cudd/cuddClip.c
@@ -0,0 +1,531 @@
+/**CFile***********************************************************************
+
+ FileName [cuddClip.c]
+
+ PackageName [cudd]
+
+ Synopsis [Clipping functions.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_bddClippingAnd()
+ <li> Cudd_bddClippingAndAbstract()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddBddClippingAnd()
+ <li> cuddBddClippingAndAbstract()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> cuddBddClippingAndRecur()
+ <li> cuddBddClipAndAbsRecur()
+ </ul>
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddClip.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static DdNode * cuddBddClippingAndRecur ARGS((DdManager *manager, DdNode *f, DdNode *g, int distance, int direction));
+static DdNode * cuddBddClipAndAbsRecur ARGS((DdManager *manager, DdNode *f, DdNode *g, DdNode *cube, int distance, int direction));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Approximates the conjunction of two BDDs f and g.]
+
+ Description [Approximates the conjunction of two BDDs f and g. Returns a
+ pointer to the resulting BDD if successful; NULL if the intermediate
+ result blows up.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddAnd]
+
+******************************************************************************/
+DdNode *
+Cudd_bddClippingAnd(
+ DdManager * dd /* manager */,
+ DdNode * f /* first conjunct */,
+ DdNode * g /* second conjunct */,
+ int maxDepth /* maximum recursion depth */,
+ int direction /* under (0) or over (1) approximation */)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddClippingAnd(dd,f,g,maxDepth,direction);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddClippingAnd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Approximates the conjunction of two BDDs f and g and
+ simultaneously abstracts the variables in cube.]
+
+ Description [Approximates the conjunction of two BDDs f and g and
+ simultaneously abstracts the variables in cube. The variables are
+ existentially abstracted. Returns a pointer to the resulting BDD if
+ successful; NULL if the intermediate result blows up.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddAndAbstract Cudd_bddClippingAnd]
+
+******************************************************************************/
+DdNode *
+Cudd_bddClippingAndAbstract(
+ DdManager * dd /* manager */,
+ DdNode * f /* first conjunct */,
+ DdNode * g /* second conjunct */,
+ DdNode * cube /* cube of variables to be abstracted */,
+ int maxDepth /* maximum recursion depth */,
+ int direction /* under (0) or over (1) approximation */)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddClippingAndAbstract(dd,f,g,cube,maxDepth,direction);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddClippingAndAbstract */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Approximates the conjunction of two BDDs f and g.]
+
+ Description [Approximates the conjunction of two BDDs f and g. Returns a
+ pointer to the resulting BDD if successful; NULL if the intermediate
+ result blows up.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddClippingAnd]
+
+******************************************************************************/
+DdNode *
+cuddBddClippingAnd(
+ DdManager * dd /* manager */,
+ DdNode * f /* first conjunct */,
+ DdNode * g /* second conjunct */,
+ int maxDepth /* maximum recursion depth */,
+ int direction /* under (0) or over (1) approximation */)
+{
+ DdNode *res;
+
+ res = cuddBddClippingAndRecur(dd,f,g,maxDepth,direction);
+
+ return(res);
+
+} /* end of cuddBddClippingAnd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Approximates the conjunction of two BDDs f and g and
+ simultaneously abstracts the variables in cube.]
+
+ Description [Approximates the conjunction of two BDDs f and g and
+ simultaneously abstracts the variables in cube. Returns a
+ pointer to the resulting BDD if successful; NULL if the intermediate
+ result blows up.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddClippingAndAbstract]
+
+******************************************************************************/
+DdNode *
+cuddBddClippingAndAbstract(
+ DdManager * dd /* manager */,
+ DdNode * f /* first conjunct */,
+ DdNode * g /* second conjunct */,
+ DdNode * cube /* cube of variables to be abstracted */,
+ int maxDepth /* maximum recursion depth */,
+ int direction /* under (0) or over (1) approximation */)
+{
+ DdNode *res;
+
+ res = cuddBddClipAndAbsRecur(dd,f,g,cube,maxDepth,direction);
+
+ return(res);
+
+} /* end of cuddBddClippingAndAbstract */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_bddClippingAnd.]
+
+ Description [Implements the recursive step of Cudd_bddClippingAnd by taking
+ the conjunction of two BDDs. Returns a pointer to the result is
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddBddClippingAnd]
+
+******************************************************************************/
+static DdNode *
+cuddBddClippingAndRecur(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * g,
+ int distance,
+ int direction)
+{
+ DdNode *F, *ft, *fe, *G, *gt, *ge;
+ DdNode *one, *zero, *r, *t, *e;
+ unsigned int topf, topg, index;
+ DdNode *(*cacheOp)(DdManager *, DdNode *, DdNode *);
+
+ statLine(manager);
+ one = DD_ONE(manager);
+ zero = Cudd_Not(one);
+
+ /* Terminal cases. */
+ if (f == zero || g == zero || f == Cudd_Not(g)) return(zero);
+ if (f == g || g == one) return(f);
+ if (f == one) return(g);
+ if (distance == 0) {
+ /* One last attempt at returning the right result. We sort of
+ ** cheat by calling Cudd_bddLeq. */
+ if (Cudd_bddLeq(manager,f,g)) return(f);
+ if (Cudd_bddLeq(manager,g,f)) return(g);
+ if (direction == 1) {
+ if (Cudd_bddLeq(manager,f,Cudd_Not(g)) ||
+ Cudd_bddLeq(manager,g,Cudd_Not(f))) return(zero);
+ }
+ return(Cudd_NotCond(one,(direction == 0)));
+ }
+
+ /* At this point f and g are not constant. */
+ distance--;
+
+ /* Check cache. Try to increase cache efficiency by sorting the
+ ** pointers. */
+ if (f > g) {
+ DdNode *tmp = f;
+ f = g; g = tmp;
+ }
+ F = Cudd_Regular(f);
+ G = Cudd_Regular(g);
+ cacheOp = (DdNode *(*)(DdManager *, DdNode *, DdNode *))
+ (direction ? Cudd_bddClippingAnd : cuddBddClippingAnd);
+ if (F->ref != 1 || G->ref != 1) {
+ r = cuddCacheLookup2(manager, cacheOp, f, g);
+ if (r != NULL) return(r);
+ }
+
+ /* Here we can skip the use of cuddI, because the operands are known
+ ** to be non-constant.
+ */
+ topf = manager->perm[F->index];
+ topg = manager->perm[G->index];
+
+ /* Compute cofactors. */
+ if (topf <= topg) {
+ index = F->index;
+ ft = cuddT(F);
+ fe = cuddE(F);
+ if (Cudd_IsComplement(f)) {
+ ft = Cudd_Not(ft);
+ fe = Cudd_Not(fe);
+ }
+ } else {
+ index = G->index;
+ ft = fe = f;
+ }
+
+ if (topg <= topf) {
+ gt = cuddT(G);
+ ge = cuddE(G);
+ if (Cudd_IsComplement(g)) {
+ gt = Cudd_Not(gt);
+ ge = Cudd_Not(ge);
+ }
+ } else {
+ gt = ge = g;
+ }
+
+ t = cuddBddClippingAndRecur(manager, ft, gt, distance, direction);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ e = cuddBddClippingAndRecur(manager, fe, ge, distance, direction);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(manager, t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ if (t == e) {
+ r = t;
+ } else {
+ if (Cudd_IsComplement(t)) {
+ r = cuddUniqueInter(manager,(int)index,Cudd_Not(t),Cudd_Not(e));
+ if (r == NULL) {
+ Cudd_RecursiveDeref(manager, t);
+ Cudd_RecursiveDeref(manager, e);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = cuddUniqueInter(manager,(int)index,t,e);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(manager, t);
+ Cudd_RecursiveDeref(manager, e);
+ return(NULL);
+ }
+ }
+ }
+ cuddDeref(e);
+ cuddDeref(t);
+ if (F->ref != 1 || G->ref != 1)
+ cuddCacheInsert2(manager, cacheOp, f, g, r);
+ return(r);
+
+} /* end of cuddBddClippingAndRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Approximates the AND of two BDDs and simultaneously abstracts the
+ variables in cube.]
+
+ Description [Approximates the AND of two BDDs and simultaneously
+ abstracts the variables in cube. The variables are existentially
+ abstracted. Returns a pointer to the result is successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddClippingAndAbstract]
+
+******************************************************************************/
+static DdNode *
+cuddBddClipAndAbsRecur(
+ DdManager * manager,
+ DdNode * f,
+ DdNode * g,
+ DdNode * cube,
+ int distance,
+ int direction)
+{
+ DdNode *F, *ft, *fe, *G, *gt, *ge;
+ DdNode *one, *zero, *r, *t, *e, *Cube;
+ unsigned int topf, topg, topcube, top, index;
+ ptruint cacheTag;
+
+ statLine(manager);
+ one = DD_ONE(manager);
+ zero = Cudd_Not(one);
+
+ /* Terminal cases. */
+ if (f == zero || g == zero || f == Cudd_Not(g)) return(zero);
+ if (f == one && g == one) return(one);
+ if (cube == one) {
+ return(cuddBddClippingAndRecur(manager, f, g, distance, direction));
+ }
+ if (f == one || f == g) {
+ return (cuddBddExistAbstractRecur(manager, g, cube));
+ }
+ if (g == one) {
+ return (cuddBddExistAbstractRecur(manager, f, cube));
+ }
+ if (distance == 0) return(Cudd_NotCond(one,(direction == 0)));
+
+ /* At this point f, g, and cube are not constant. */
+ distance--;
+
+ /* Check cache. */
+ if (f > g) { /* Try to increase cache efficiency. */
+ DdNode *tmp = f;
+ f = g; g = tmp;
+ }
+ F = Cudd_Regular(f);
+ G = Cudd_Regular(g);
+ cacheTag = direction ? DD_BDD_CLIPPING_AND_ABSTRACT_UP_TAG :
+ DD_BDD_CLIPPING_AND_ABSTRACT_DOWN_TAG;
+ if (F->ref != 1 || G->ref != 1) {
+ r = cuddCacheLookup(manager, cacheTag,
+ f, g, cube);
+ if (r != NULL) {
+ return(r);
+ }
+ }
+
+ /* Here we can skip the use of cuddI, because the operands are known
+ ** to be non-constant.
+ */
+ topf = manager->perm[F->index];
+ topg = manager->perm[G->index];
+ top = ddMin(topf, topg);
+ topcube = manager->perm[cube->index];
+
+ if (topcube < top) {
+ return(cuddBddClipAndAbsRecur(manager, f, g, cuddT(cube),
+ distance, direction));
+ }
+ /* Now, topcube >= top. */
+
+ if (topf == top) {
+ index = F->index;
+ ft = cuddT(F);
+ fe = cuddE(F);
+ if (Cudd_IsComplement(f)) {
+ ft = Cudd_Not(ft);
+ fe = Cudd_Not(fe);
+ }
+ } else {
+ index = G->index;
+ ft = fe = f;
+ }
+
+ if (topg == top) {
+ gt = cuddT(G);
+ ge = cuddE(G);
+ if (Cudd_IsComplement(g)) {
+ gt = Cudd_Not(gt);
+ ge = Cudd_Not(ge);
+ }
+ } else {
+ gt = ge = g;
+ }
+
+ if (topcube == top) {
+ Cube = cuddT(cube);
+ } else {
+ Cube = cube;
+ }
+
+ t = cuddBddClipAndAbsRecur(manager, ft, gt, Cube, distance, direction);
+ if (t == NULL) return(NULL);
+
+ /* Special case: 1 OR anything = 1. Hence, no need to compute
+ ** the else branch if t is 1.
+ */
+ if (t == one && topcube == top) {
+ if (F->ref != 1 || G->ref != 1)
+ cuddCacheInsert(manager, cacheTag, f, g, cube, one);
+ return(one);
+ }
+ cuddRef(t);
+
+ e = cuddBddClipAndAbsRecur(manager, fe, ge, Cube, distance, direction);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(manager, t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ if (topcube == top) { /* abstract */
+ r = cuddBddClippingAndRecur(manager, Cudd_Not(t), Cudd_Not(e),
+ distance, (direction == 0));
+ if (r == NULL) {
+ Cudd_RecursiveDeref(manager, t);
+ Cudd_RecursiveDeref(manager, e);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ cuddRef(r);
+ Cudd_RecursiveDeref(manager, t);
+ Cudd_RecursiveDeref(manager, e);
+ cuddDeref(r);
+ } else if (t == e) {
+ r = t;
+ cuddDeref(t);
+ cuddDeref(e);
+ } else {
+ if (Cudd_IsComplement(t)) {
+ r = cuddUniqueInter(manager,(int)index,Cudd_Not(t),Cudd_Not(e));
+ if (r == NULL) {
+ Cudd_RecursiveDeref(manager, t);
+ Cudd_RecursiveDeref(manager, e);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = cuddUniqueInter(manager,(int)index,t,e);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(manager, t);
+ Cudd_RecursiveDeref(manager, e);
+ return(NULL);
+ }
+ }
+ cuddDeref(e);
+ cuddDeref(t);
+ }
+ if (F->ref != 1 || G->ref != 1)
+ cuddCacheInsert(manager, cacheTag, f, g, cube, r);
+ return (r);
+
+} /* end of cuddBddClipAndAbsRecur */
+
diff --git a/src/bdd/cudd/cuddCof.c b/src/bdd/cudd/cuddCof.c
new file mode 100644
index 00000000..0dfeff6c
--- /dev/null
+++ b/src/bdd/cudd/cuddCof.c
@@ -0,0 +1,300 @@
+/**CFile***********************************************************************
+
+ FileName [cuddCof.c]
+
+ PackageName [cudd]
+
+ Synopsis [Cofactoring functions.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_Cofactor()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddGetBranches()
+ <li> cuddCheckCube()
+ <li> cuddCofactorRecur()
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddCof.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the cofactor of f with respect to g.]
+
+ Description [Computes the cofactor of f with respect to g; g must be
+ the BDD or the ADD of a cube. Returns a pointer to the cofactor if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddConstrain Cudd_bddRestrict]
+
+******************************************************************************/
+DdNode *
+Cudd_Cofactor(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res,*zero;
+
+ zero = Cudd_Not(DD_ONE(dd));
+ if (g == zero || g == DD_ZERO(dd)) {
+ (void) fprintf(dd->err,"Cudd_Cofactor: Invalid restriction 1\n");
+ dd->errorCode = CUDD_INVALID_ARG;
+ return(NULL);
+ }
+ do {
+ dd->reordered = 0;
+ res = cuddCofactorRecur(dd,f,g);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_Cofactor */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the children of g.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+cuddGetBranches(
+ DdNode * g,
+ DdNode ** g1,
+ DdNode ** g0)
+{
+ DdNode *G = Cudd_Regular(g);
+
+ *g1 = cuddT(G);
+ *g0 = cuddE(G);
+ if (Cudd_IsComplement(g)) {
+ *g1 = Cudd_Not(*g1);
+ *g0 = Cudd_Not(*g0);
+ }
+
+} /* end of cuddGetBranches */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether g is the BDD of a cube.]
+
+ Description [Checks whether g is the BDD of a cube. Returns 1 in case
+ of success; 0 otherwise. The constant 1 is a valid cube, but all other
+ constant functions cause cuddCheckCube to return 0.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddCheckCube(
+ DdManager * dd,
+ DdNode * g)
+{
+ DdNode *g1,*g0,*one,*zero;
+
+ one = DD_ONE(dd);
+ if (g == one) return(1);
+ if (Cudd_IsConstant(g)) return(0);
+
+ zero = Cudd_Not(one);
+ cuddGetBranches(g,&g1,&g0);
+
+ if (g0 == zero) {
+ return(cuddCheckCube(dd, g1));
+ }
+ if (g1 == zero) {
+ return(cuddCheckCube(dd, g0));
+ }
+ return(0);
+
+} /* end of cuddCheckCube */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_Cofactor.]
+
+ Description [Performs the recursive step of Cudd_Cofactor. Returns a
+ pointer to the cofactor if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Cofactor]
+
+******************************************************************************/
+DdNode *
+cuddCofactorRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *one,*zero,*F,*G,*g1,*g0,*f1,*f0,*t,*e,*r;
+ unsigned int topf,topg;
+ int comple;
+
+ statLine(dd);
+ F = Cudd_Regular(f);
+ if (cuddIsConstant(F)) return(f);
+
+ one = DD_ONE(dd);
+
+ /* The invariant g != 0 is true on entry to this procedure and is
+ ** recursively maintained by it. Therefore it suffices to test g
+ ** against one to make sure it is not constant.
+ */
+ if (g == one) return(f);
+ /* From now on, f and g are known not to be constants. */
+
+ comple = f != F;
+ r = cuddCacheLookup2(dd,Cudd_Cofactor,F,g);
+ if (r != NULL) {
+ return(Cudd_NotCond(r,comple));
+ }
+
+ topf = dd->perm[F->index];
+ G = Cudd_Regular(g);
+ topg = dd->perm[G->index];
+
+ /* We take the cofactors of F because we are going to rely on
+ ** the fact that the cofactors of the complement are the complements
+ ** of the cofactors to better utilize the cache. Variable comple
+ ** remembers whether we have to complement the result or not.
+ */
+ if (topf <= topg) {
+ f1 = cuddT(F); f0 = cuddE(F);
+ } else {
+ f1 = f0 = F;
+ }
+ if (topg <= topf) {
+ g1 = cuddT(G); g0 = cuddE(G);
+ if (g != G) { g1 = Cudd_Not(g1); g0 = Cudd_Not(g0); }
+ } else {
+ g1 = g0 = g;
+ }
+
+ zero = Cudd_Not(one);
+ if (topf >= topg) {
+ if (g0 == zero || g0 == DD_ZERO(dd)) {
+ r = cuddCofactorRecur(dd, f1, g1);
+ } else if (g1 == zero || g1 == DD_ZERO(dd)) {
+ r = cuddCofactorRecur(dd, f0, g0);
+ } else {
+ (void) fprintf(dd->out,
+ "Cudd_Cofactor: Invalid restriction 2\n");
+ dd->errorCode = CUDD_INVALID_ARG;
+ return(NULL);
+ }
+ if (r == NULL) return(NULL);
+ } else /* if (topf < topg) */ {
+ t = cuddCofactorRecur(dd, f1, g);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ e = cuddCofactorRecur(dd, f0, g);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ if (t == e) {
+ r = t;
+ } else if (Cudd_IsComplement(t)) {
+ r = cuddUniqueInter(dd,(int)F->index,Cudd_Not(t),Cudd_Not(e));
+ if (r != NULL)
+ r = Cudd_Not(r);
+ } else {
+ r = cuddUniqueInter(dd,(int)F->index,t,e);
+ }
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd ,e);
+ Cudd_RecursiveDeref(dd ,t);
+ return(NULL);
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+ }
+
+ cuddCacheInsert2(dd,Cudd_Cofactor,F,g,r);
+
+ return(Cudd_NotCond(r,comple));
+
+} /* end of cuddCofactorRecur */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
diff --git a/src/bdd/cudd/cuddCompose.c b/src/bdd/cudd/cuddCompose.c
new file mode 100644
index 00000000..11c6cb7b
--- /dev/null
+++ b/src/bdd/cudd/cuddCompose.c
@@ -0,0 +1,1722 @@
+/**CFile***********************************************************************
+
+ FileName [cuddCompose.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functional composition and variable permutation of DDs.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_bddCompose()
+ <li> Cudd_addCompose()
+ <li> Cudd_addPermute()
+ <li> Cudd_addSwapVariables()
+ <li> Cudd_bddPermute()
+ <li> Cudd_bddVarMap()
+ <li> Cudd_SetVarMap()
+ <li> Cudd_bddSwapVariables()
+ <li> Cudd_bddAdjPermuteX()
+ <li> Cudd_addVectorCompose()
+ <li> Cudd_addGeneralVectorCompose()
+ <li> Cudd_addNonSimCompose()
+ <li> Cudd_bddVectorCompose()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddBddComposeRecur()
+ <li> cuddAddComposeRecur()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> cuddAddPermuteRecur()
+ <li> cuddBddPermuteRecur()
+ <li> cuddBddVarMapRecur()
+ <li> cuddAddVectorComposeRecur()
+ <li> cuddAddGeneralVectorComposeRecur()
+ <li> cuddAddNonSimComposeRecur()
+ <li> cuddBddVectorComposeRecur()
+ <li> ddIsIthAddVar()
+ <li> ddIsIthAddVarPair()
+ </ul>
+ The permutation functions use a local cache because the results to
+ be remembered depend on the permutation being applied. Since the
+ permutation is just an array, it cannot be stored in the global
+ cache. There are different procedured for BDDs and ADDs. This is
+ because bddPermuteRecur uses cuddBddIteRecur. If this were changed,
+ the procedures could be merged.]
+
+ Author [Fabio Somenzi and Kavita Ravi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddCompose.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+#ifdef DD_DEBUG
+static int addPermuteRecurHits;
+static int bddPermuteRecurHits;
+static int bddVectorComposeHits;
+static int addVectorComposeHits;
+
+static int addGeneralVectorComposeHits;
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static DdNode * cuddAddPermuteRecur ARGS((DdManager *manager, DdHashTable *table, DdNode *node, int *permut));
+static DdNode * cuddBddPermuteRecur ARGS((DdManager *manager, DdHashTable *table, DdNode *node, int *permut));
+static DdNode * cuddBddVarMapRecur ARGS((DdManager *manager, DdNode *f));
+static DdNode * cuddAddVectorComposeRecur ARGS((DdManager *dd, DdHashTable *table, DdNode *f, DdNode **vector, int deepest));
+static DdNode * cuddAddNonSimComposeRecur ARGS((DdManager *dd, DdNode *f, DdNode **vector, DdNode *key, DdNode *cube, int lastsub));
+static DdNode * cuddBddVectorComposeRecur ARGS((DdManager *dd, DdHashTable *table, DdNode *f, DdNode **vector, int deepest));
+DD_INLINE static int ddIsIthAddVar ARGS((DdManager *dd, DdNode *f, unsigned int i));
+
+static DdNode * cuddAddGeneralVectorComposeRecur ARGS((DdManager *dd, DdHashTable *table, DdNode *f, DdNode **vectorOn, DdNode **vectorOff, int deepest));
+DD_INLINE static int ddIsIthAddVarPair ARGS((DdManager *dd, DdNode *f, DdNode *g, unsigned int i));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Substitutes g for x_v in the BDD for f.]
+
+ Description [Substitutes g for x_v in the BDD for f. v is the index of the
+ variable to be substituted. Cudd_bddCompose passes the corresponding
+ projection function to the recursive procedure, so that the cache may
+ be used. Returns the composed BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addCompose]
+
+******************************************************************************/
+DdNode *
+Cudd_bddCompose(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ int v)
+{
+ DdNode *proj, *res;
+
+ /* Sanity check. */
+ if (v < 0 || v > dd->size) return(NULL);
+
+ proj = dd->vars[v];
+ do {
+ dd->reordered = 0;
+ res = cuddBddComposeRecur(dd,f,g,proj);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddCompose */
+
+
+/**Function********************************************************************
+
+ Synopsis [Substitutes g for x_v in the ADD for f.]
+
+ Description [Substitutes g for x_v in the ADD for f. v is the index of the
+ variable to be substituted. g must be a 0-1 ADD. Cudd_bddCompose passes
+ the corresponding projection function to the recursive procedure, so
+ that the cache may be used. Returns the composed ADD if successful;
+ NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddCompose]
+
+******************************************************************************/
+DdNode *
+Cudd_addCompose(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ int v)
+{
+ DdNode *proj, *res;
+
+ /* Sanity check. */
+ if (v < 0 || v > dd->size) return(NULL);
+
+ proj = dd->vars[v];
+ do {
+ dd->reordered = 0;
+ res = cuddAddComposeRecur(dd,f,g,proj);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_addCompose */
+
+
+/**Function********************************************************************
+
+ Synopsis [Permutes the variables of an ADD.]
+
+ Description [Given a permutation in array permut, creates a new ADD
+ with permuted variables. There should be an entry in array permut
+ for each variable in the manager. The i-th entry of permut holds the
+ index of the variable that is to substitute the i-th
+ variable. Returns a pointer to the resulting ADD if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddPermute Cudd_addSwapVariables]
+
+******************************************************************************/
+DdNode *
+Cudd_addPermute(
+ DdManager * manager,
+ DdNode * node,
+ int * permut)
+{
+ DdHashTable *table;
+ DdNode *res;
+
+ do {
+ manager->reordered = 0;
+ table = cuddHashTableInit(manager,1,2);
+ if (table == NULL) return(NULL);
+ /* Recursively solve the problem. */
+ res = cuddAddPermuteRecur(manager,table,node,permut);
+ if (res != NULL) cuddRef(res);
+ /* Dispose of local cache. */
+ cuddHashTableQuit(table);
+ } while (manager->reordered == 1);
+
+ if (res != NULL) cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_addPermute */
+
+
+/**Function********************************************************************
+
+ Synopsis [Swaps two sets of variables of the same size (x and y) in
+ the ADD f.]
+
+ Description [Swaps two sets of variables of the same size (x and y) in
+ the ADD f. The size is given by n. The two sets of variables are
+ assumed to be disjoint. Returns a pointer to the resulting ADD if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addPermute Cudd_bddSwapVariables]
+
+******************************************************************************/
+DdNode *
+Cudd_addSwapVariables(
+ DdManager * dd,
+ DdNode * f,
+ DdNode ** x,
+ DdNode ** y,
+ int n)
+{
+ DdNode *swapped;
+ int i, j, k;
+ int *permut;
+
+ permut = ALLOC(int,dd->size);
+ if (permut == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < dd->size; i++) permut[i] = i;
+ for (i = 0; i < n; i++) {
+ j = x[i]->index;
+ k = y[i]->index;
+ permut[j] = k;
+ permut[k] = j;
+ }
+
+ swapped = Cudd_addPermute(dd,f,permut);
+ FREE(permut);
+
+ return(swapped);
+
+} /* end of Cudd_addSwapVariables */
+
+
+/**Function********************************************************************
+
+ Synopsis [Permutes the variables of a BDD.]
+
+ Description [Given a permutation in array permut, creates a new BDD
+ with permuted variables. There should be an entry in array permut
+ for each variable in the manager. The i-th entry of permut holds the
+ index of the variable that is to substitute the i-th variable.
+ Returns a pointer to the resulting BDD if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addPermute Cudd_bddSwapVariables]
+
+******************************************************************************/
+DdNode *
+Cudd_bddPermute(
+ DdManager * manager,
+ DdNode * node,
+ int * permut)
+{
+ DdHashTable *table;
+ DdNode *res;
+
+ do {
+ manager->reordered = 0;
+ table = cuddHashTableInit(manager,1,2);
+ if (table == NULL) return(NULL);
+ res = cuddBddPermuteRecur(manager,table,node,permut);
+ if (res != NULL) cuddRef(res);
+ /* Dispose of local cache. */
+ cuddHashTableQuit(table);
+
+ } while (manager->reordered == 1);
+
+ if (res != NULL) cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_bddPermute */
+
+
+/**Function********************************************************************
+
+ Synopsis [Remaps the variables of a BDD using the default variable map.]
+
+ Description [Remaps the variables of a BDD using the default
+ variable map. A typical use of this function is to swap two sets of
+ variables. The variable map must be registered with Cudd_SetVarMap.
+ Returns a pointer to the resulting BDD if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddPermute Cudd_bddSwapVariables Cudd_SetVarMap]
+
+******************************************************************************/
+DdNode *
+Cudd_bddVarMap(
+ DdManager * manager /* DD manager */,
+ DdNode * f /* function in which to remap variables */)
+{
+ DdNode *res;
+
+ if (manager->map == NULL) return(NULL);
+ do {
+ manager->reordered = 0;
+ res = cuddBddVarMapRecur(manager, f);
+ } while (manager->reordered == 1);
+
+ return(res);
+
+} /* end of Cudd_bddVarMap */
+
+
+/**Function********************************************************************
+
+ Synopsis [Registers a variable mapping with the manager.]
+
+ Description [Registers with the manager a variable mapping described
+ by two sets of variables. This variable mapping is then used by
+ functions like Cudd_bddVarMap. This function is convenient for
+ those applications that perform the same mapping several times.
+ However, if several different permutations are used, it may be more
+ efficient not to rely on the registered mapping, because changing
+ mapping causes the cache to be cleared. (The initial setting,
+ however, does not clear the cache.) The two sets of variables (x and
+ y) must have the same size (x and y). The size is given by n. The
+ two sets of variables are normally disjoint, but this restriction is
+ not imposeded by the function. When new variables are created, the
+ map is automatically extended (each new variable maps to
+ itself). The typical use, however, is to wait until all variables
+ are created, and then create the map. Returns 1 if the mapping is
+ successfully registered with the manager; 0 otherwise.]
+
+ SideEffects [Modifies the manager. May clear the cache.]
+
+ SeeAlso [Cudd_bddVarMap Cudd_bddPermute Cudd_bddSwapVariables]
+
+******************************************************************************/
+int
+Cudd_SetVarMap (
+ DdManager *manager /* DD manager */,
+ DdNode **x /* first array of variables */,
+ DdNode **y /* second array of variables */,
+ int n /* length of both arrays */)
+{
+ int i;
+
+ if (manager->map != NULL) {
+ cuddCacheFlush(manager);
+ } else {
+ manager->map = ALLOC(int,manager->maxSize);
+ if (manager->map == NULL) {
+ manager->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ manager->memused += sizeof(int) * manager->maxSize;
+ }
+ /* Initialize the map to the identity. */
+ for (i = 0; i < manager->size; i++) {
+ manager->map[i] = i;
+ }
+ /* Create the map. */
+ for (i = 0; i < n; i++) {
+ manager->map[x[i]->index] = y[i]->index;
+ manager->map[y[i]->index] = x[i]->index;
+ }
+ return(1);
+
+} /* end of Cudd_SetVarMap */
+
+
+/**Function********************************************************************
+
+ Synopsis [Swaps two sets of variables of the same size (x and y) in
+ the BDD f.]
+
+ Description [Swaps two sets of variables of the same size (x and y)
+ in the BDD f. The size is given by n. The two sets of variables are
+ assumed to be disjoint. Returns a pointer to the resulting BDD if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddPermute Cudd_addSwapVariables]
+
+******************************************************************************/
+DdNode *
+Cudd_bddSwapVariables(
+ DdManager * dd,
+ DdNode * f,
+ DdNode ** x,
+ DdNode ** y,
+ int n)
+{
+ DdNode *swapped;
+ int i, j, k;
+ int *permut;
+
+ permut = ALLOC(int,dd->size);
+ if (permut == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < dd->size; i++) permut[i] = i;
+ for (i = 0; i < n; i++) {
+ j = x[i]->index;
+ k = y[i]->index;
+ permut[j] = k;
+ permut[k] = j;
+ }
+
+ swapped = Cudd_bddPermute(dd,f,permut);
+ FREE(permut);
+
+ return(swapped);
+
+} /* end of Cudd_bddSwapVariables */
+
+
+/**Function********************************************************************
+
+ Synopsis [Rearranges a set of variables in the BDD B.]
+
+ Description [Rearranges a set of variables in the BDD B. The size of
+ the set is given by n. This procedure is intended for the
+ `randomization' of the priority functions. Returns a pointer to the
+ BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddPermute Cudd_bddSwapVariables
+ Cudd_Dxygtdxz Cudd_Dxygtdyz Cudd_PrioritySelect]
+
+******************************************************************************/
+DdNode *
+Cudd_bddAdjPermuteX(
+ DdManager * dd,
+ DdNode * B,
+ DdNode ** x,
+ int n)
+{
+ DdNode *swapped;
+ int i, j, k;
+ int *permut;
+
+ permut = ALLOC(int,dd->size);
+ if (permut == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < dd->size; i++) permut[i] = i;
+ for (i = 0; i < n-2; i += 3) {
+ j = x[i]->index;
+ k = x[i+1]->index;
+ permut[j] = k;
+ permut[k] = j;
+ }
+
+ swapped = Cudd_bddPermute(dd,B,permut);
+ FREE(permut);
+
+ return(swapped);
+
+} /* end of Cudd_bddAdjPermuteX */
+
+
+/**Function********************************************************************
+
+ Synopsis [Composes an ADD with a vector of 0-1 ADDs.]
+
+ Description [Given a vector of 0-1 ADDs, creates a new ADD by
+ substituting the 0-1 ADDs for the variables of the ADD f. There
+ should be an entry in vector for each variable in the manager.
+ If no substitution is sought for a given variable, the corresponding
+ projection function should be specified in the vector.
+ This function implements simultaneous composition.
+ Returns a pointer to the resulting ADD if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addNonSimCompose Cudd_addPermute Cudd_addCompose
+ Cudd_bddVectorCompose]
+
+******************************************************************************/
+DdNode *
+Cudd_addVectorCompose(
+ DdManager * dd,
+ DdNode * f,
+ DdNode ** vector)
+{
+ DdHashTable *table;
+ DdNode *res;
+ int deepest;
+ int i;
+
+ do {
+ dd->reordered = 0;
+ /* Initialize local cache. */
+ table = cuddHashTableInit(dd,1,2);
+ if (table == NULL) return(NULL);
+
+ /* Find deepest real substitution. */
+ for (deepest = dd->size - 1; deepest >= 0; deepest--) {
+ i = dd->invperm[deepest];
+ if (!ddIsIthAddVar(dd,vector[i],i)) {
+ break;
+ }
+ }
+
+ /* Recursively solve the problem. */
+ res = cuddAddVectorComposeRecur(dd,table,f,vector,deepest);
+ if (res != NULL) cuddRef(res);
+
+ /* Dispose of local cache. */
+ cuddHashTableQuit(table);
+ } while (dd->reordered == 1);
+
+ if (res != NULL) cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_addVectorCompose */
+
+
+/**Function********************************************************************
+
+ Synopsis [Composes an ADD with a vector of ADDs.]
+
+ Description [Given a vector of ADDs, creates a new ADD by substituting the
+ ADDs for the variables of the ADD f. vectorOn contains ADDs to be substituted
+ for the x_v and vectorOff the ADDs to be substituted for x_v'. There should
+ be an entry in vector for each variable in the manager. If no substitution
+ is sought for a given variable, the corresponding projection function should
+ be specified in the vector. This function implements simultaneous
+ composition. Returns a pointer to the resulting ADD if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addVectorCompose Cudd_addNonSimCompose Cudd_addPermute
+ Cudd_addCompose Cudd_bddVectorCompose]
+
+******************************************************************************/
+DdNode *
+Cudd_addGeneralVectorCompose(
+ DdManager * dd,
+ DdNode * f,
+ DdNode ** vectorOn,
+ DdNode ** vectorOff)
+{
+ DdHashTable *table;
+ DdNode *res;
+ int deepest;
+ int i;
+
+ do {
+ dd->reordered = 0;
+ /* Initialize local cache. */
+ table = cuddHashTableInit(dd,1,2);
+ if (table == NULL) return(NULL);
+
+ /* Find deepest real substitution. */
+ for (deepest = dd->size - 1; deepest >= 0; deepest--) {
+ i = dd->invperm[deepest];
+ if (!ddIsIthAddVarPair(dd,vectorOn[i],vectorOff[i],i)) {
+ break;
+ }
+ }
+
+ /* Recursively solve the problem. */
+ res = cuddAddGeneralVectorComposeRecur(dd,table,f,vectorOn,
+ vectorOff,deepest);
+ if (res != NULL) cuddRef(res);
+
+ /* Dispose of local cache. */
+ cuddHashTableQuit(table);
+ } while (dd->reordered == 1);
+
+ if (res != NULL) cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_addGeneralVectorCompose */
+
+
+/**Function********************************************************************
+
+ Synopsis [Composes an ADD with a vector of 0-1 ADDs.]
+
+ Description [Given a vector of 0-1 ADDs, creates a new ADD by
+ substituting the 0-1 ADDs for the variables of the ADD f. There
+ should be an entry in vector for each variable in the manager.
+ This function implements non-simultaneous composition. If any of the
+ functions being composed depends on any of the variables being
+ substituted, then the result depends on the order of composition,
+ which in turn depends on the variable order: The variables farther from
+ the roots in the order are substituted first.
+ Returns a pointer to the resulting ADD if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addVectorCompose Cudd_addPermute Cudd_addCompose]
+
+******************************************************************************/
+DdNode *
+Cudd_addNonSimCompose(
+ DdManager * dd,
+ DdNode * f,
+ DdNode ** vector)
+{
+ DdNode *cube, *key, *var, *tmp, *piece;
+ DdNode *res;
+ int i, lastsub;
+
+ /* The cache entry for this function is composed of three parts:
+ ** f itself, the replacement relation, and the cube of the
+ ** variables being substituted.
+ ** The replacement relation is the product of the terms (yi EXNOR gi).
+ ** This apporach allows us to use the global cache for this function,
+ ** with great savings in memory with respect to using arrays for the
+ ** cache entries.
+ ** First we build replacement relation and cube of substituted
+ ** variables from the vector specifying the desired composition.
+ */
+ key = DD_ONE(dd);
+ cuddRef(key);
+ cube = DD_ONE(dd);
+ cuddRef(cube);
+ for (i = (int) dd->size - 1; i >= 0; i--) {
+ if (ddIsIthAddVar(dd,vector[i],(unsigned int)i)) {
+ continue;
+ }
+ var = Cudd_addIthVar(dd,i);
+ if (var == NULL) {
+ Cudd_RecursiveDeref(dd,key);
+ Cudd_RecursiveDeref(dd,cube);
+ return(NULL);
+ }
+ cuddRef(var);
+ /* Update cube. */
+ tmp = Cudd_addApply(dd,Cudd_addTimes,var,cube);
+ if (tmp == NULL) {
+ Cudd_RecursiveDeref(dd,key);
+ Cudd_RecursiveDeref(dd,cube);
+ Cudd_RecursiveDeref(dd,var);
+ return(NULL);
+ }
+ cuddRef(tmp);
+ Cudd_RecursiveDeref(dd,cube);
+ cube = tmp;
+ /* Update replacement relation. */
+ piece = Cudd_addApply(dd,Cudd_addXnor,var,vector[i]);
+ if (piece == NULL) {
+ Cudd_RecursiveDeref(dd,key);
+ Cudd_RecursiveDeref(dd,var);
+ return(NULL);
+ }
+ cuddRef(piece);
+ Cudd_RecursiveDeref(dd,var);
+ tmp = Cudd_addApply(dd,Cudd_addTimes,key,piece);
+ if (tmp == NULL) {
+ Cudd_RecursiveDeref(dd,key);
+ Cudd_RecursiveDeref(dd,piece);
+ return(NULL);
+ }
+ cuddRef(tmp);
+ Cudd_RecursiveDeref(dd,key);
+ Cudd_RecursiveDeref(dd,piece);
+ key = tmp;
+ }
+
+ /* Now try composition, until no reordering occurs. */
+ do {
+ /* Find real substitution with largest index. */
+ for (lastsub = dd->size - 1; lastsub >= 0; lastsub--) {
+ if (!ddIsIthAddVar(dd,vector[lastsub],(unsigned int)lastsub)) {
+ break;
+ }
+ }
+
+ /* Recursively solve the problem. */
+ dd->reordered = 0;
+ res = cuddAddNonSimComposeRecur(dd,f,vector,key,cube,lastsub+1);
+ if (res != NULL) cuddRef(res);
+
+ } while (dd->reordered == 1);
+
+ Cudd_RecursiveDeref(dd,key);
+ Cudd_RecursiveDeref(dd,cube);
+ if (res != NULL) cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_addNonSimCompose */
+
+
+/**Function********************************************************************
+
+ Synopsis [Composes a BDD with a vector of BDDs.]
+
+ Description [Given a vector of BDDs, creates a new BDD by
+ substituting the BDDs for the variables of the BDD f. There
+ should be an entry in vector for each variable in the manager.
+ If no substitution is sought for a given variable, the corresponding
+ projection function should be specified in the vector.
+ This function implements simultaneous composition.
+ Returns a pointer to the resulting BDD if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddPermute Cudd_bddCompose Cudd_addVectorCompose]
+
+******************************************************************************/
+DdNode *
+Cudd_bddVectorCompose(
+ DdManager * dd,
+ DdNode * f,
+ DdNode ** vector)
+{
+ DdHashTable *table;
+ DdNode *res;
+ int deepest;
+ int i;
+
+ do {
+ dd->reordered = 0;
+ /* Initialize local cache. */
+ table = cuddHashTableInit(dd,1,2);
+ if (table == NULL) return(NULL);
+
+ /* Find deepest real substitution. */
+ for (deepest = dd->size - 1; deepest >= 0; deepest--) {
+ i = dd->invperm[deepest];
+ if (vector[i] != dd->vars[i]) {
+ break;
+ }
+ }
+
+ /* Recursively solve the problem. */
+ res = cuddBddVectorComposeRecur(dd,table,f,vector, deepest);
+ if (res != NULL) cuddRef(res);
+
+ /* Dispose of local cache. */
+ cuddHashTableQuit(table);
+ } while (dd->reordered == 1);
+
+ if (res != NULL) cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_bddVectorCompose */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddCompose.]
+
+ Description [Performs the recursive step of Cudd_bddCompose.
+ Exploits the fact that the composition of f' with g
+ produces the complement of the composition of f with g to better
+ utilize the cache. Returns the composed BDD if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddCompose]
+
+******************************************************************************/
+DdNode *
+cuddBddComposeRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ DdNode * proj)
+{
+ DdNode *F, *G, *f1, *f0, *g1, *g0, *r, *t, *e;
+ unsigned int v, topf, topg, topindex;
+ int comple;
+
+ statLine(dd);
+ v = dd->perm[proj->index];
+ F = Cudd_Regular(f);
+ topf = cuddI(dd,F->index);
+
+ /* Terminal case. Subsumes the test for constant f. */
+ if (topf > v) return(f);
+
+ /* We solve the problem for a regular pointer, and then complement
+ ** the result if the pointer was originally complemented.
+ */
+ comple = Cudd_IsComplement(f);
+
+ /* Check cache. */
+ r = cuddCacheLookup(dd,DD_BDD_COMPOSE_RECUR_TAG,F,g,proj);
+ if (r != NULL) {
+ return(Cudd_NotCond(r,comple));
+ }
+
+ if (topf == v) {
+ /* Compose. */
+ f1 = cuddT(F);
+ f0 = cuddE(F);
+ r = cuddBddIteRecur(dd, g, f1, f0);
+ if (r == NULL) return(NULL);
+ } else {
+ /* Compute cofactors of f and g. Remember the index of the top
+ ** variable.
+ */
+ G = Cudd_Regular(g);
+ topg = cuddI(dd,G->index);
+ if (topf > topg) {
+ topindex = G->index;
+ f1 = f0 = F;
+ } else {
+ topindex = F->index;
+ f1 = cuddT(F);
+ f0 = cuddE(F);
+ }
+ if (topg > topf) {
+ g1 = g0 = g;
+ } else {
+ g1 = cuddT(G);
+ g0 = cuddE(G);
+ if (g != G) {
+ g1 = Cudd_Not(g1);
+ g0 = Cudd_Not(g0);
+ }
+ }
+ /* Recursive step. */
+ t = cuddBddComposeRecur(dd, f1, g1, proj);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ e = cuddBddComposeRecur(dd, f0, g0, proj);
+ if (e == NULL) {
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ r = cuddBddIteRecur(dd, dd->vars[topindex], t, e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, t);
+ Cudd_IterDerefBdd(dd, e);
+ return(NULL);
+ }
+ cuddRef(r);
+ Cudd_IterDerefBdd(dd, t); /* t & e not necessarily part of r */
+ Cudd_IterDerefBdd(dd, e);
+ cuddDeref(r);
+ }
+
+ cuddCacheInsert(dd,DD_BDD_COMPOSE_RECUR_TAG,F,g,proj,r);
+
+ return(Cudd_NotCond(r,comple));
+
+} /* end of cuddBddComposeRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addCompose.]
+
+ Description [Performs the recursive step of Cudd_addCompose.
+ Returns the composed BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addCompose]
+
+******************************************************************************/
+DdNode *
+cuddAddComposeRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ DdNode * proj)
+{
+ DdNode *f1, *f0, *g1, *g0, *r, *t, *e;
+ unsigned int v, topf, topg, topindex;
+
+ statLine(dd);
+ v = dd->perm[proj->index];
+ topf = cuddI(dd,f->index);
+
+ /* Terminal case. Subsumes the test for constant f. */
+ if (topf > v) return(f);
+
+ /* Check cache. */
+ r = cuddCacheLookup(dd,DD_ADD_COMPOSE_RECUR_TAG,f,g,proj);
+ if (r != NULL) {
+ return(r);
+ }
+
+ if (topf == v) {
+ /* Compose. */
+ f1 = cuddT(f);
+ f0 = cuddE(f);
+ r = cuddAddIteRecur(dd, g, f1, f0);
+ if (r == NULL) return(NULL);
+ } else {
+ /* Compute cofactors of f and g. Remember the index of the top
+ ** variable.
+ */
+ topg = cuddI(dd,g->index);
+ if (topf > topg) {
+ topindex = g->index;
+ f1 = f0 = f;
+ } else {
+ topindex = f->index;
+ f1 = cuddT(f);
+ f0 = cuddE(f);
+ }
+ if (topg > topf) {
+ g1 = g0 = g;
+ } else {
+ g1 = cuddT(g);
+ g0 = cuddE(g);
+ }
+ /* Recursive step. */
+ t = cuddAddComposeRecur(dd, f1, g1, proj);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ e = cuddAddComposeRecur(dd, f0, g0, proj);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ if (t == e) {
+ r = t;
+ } else {
+ r = cuddUniqueInter(dd, (int) topindex, t, e);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ Cudd_RecursiveDeref(dd, e);
+ return(NULL);
+ }
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+ }
+
+ cuddCacheInsert(dd,DD_ADD_COMPOSE_RECUR_TAG,f,g,proj,r);
+
+ return(r);
+
+} /* end of cuddAddComposeRecur */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_addPermute.]
+
+ Description [ Recursively puts the ADD in the order given in the
+ array permut. Checks for trivial cases to terminate recursion, then
+ splits on the children of this node. Once the solutions for the
+ children are obtained, it puts into the current position the node
+ from the rest of the ADD that should be here. Then returns this ADD.
+ The key here is that the node being visited is NOT put in its proper
+ place by this instance, but rather is switched when its proper
+ position is reached in the recursion tree.<p>
+ The DdNode * that is returned is the same ADD as passed in as node,
+ but in the new order.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addPermute cuddBddPermuteRecur]
+
+******************************************************************************/
+static DdNode *
+cuddAddPermuteRecur(
+ DdManager * manager /* DD manager */,
+ DdHashTable * table /* computed table */,
+ DdNode * node /* ADD to be reordered */,
+ int * permut /* permutation array */)
+{
+ DdNode *T,*E;
+ DdNode *res,*var;
+ int index;
+
+ statLine(manager);
+ /* Check for terminal case of constant node. */
+ if (cuddIsConstant(node)) {
+ return(node);
+ }
+
+ /* If problem already solved, look up answer and return. */
+ if (node->ref != 1 && (res = cuddHashTableLookup1(table,node)) != NULL) {
+#ifdef DD_DEBUG
+ addPermuteRecurHits++;
+#endif
+ return(res);
+ }
+
+ /* Split and recur on children of this node. */
+ T = cuddAddPermuteRecur(manager,table,cuddT(node),permut);
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+ E = cuddAddPermuteRecur(manager,table,cuddE(node),permut);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(manager, T);
+ return(NULL);
+ }
+ cuddRef(E);
+
+ /* Move variable that should be in this position to this position
+ ** by creating a single var ADD for that variable, and calling
+ ** cuddAddIteRecur with the T and E we just created.
+ */
+ index = permut[node->index];
+ var = cuddUniqueInter(manager,index,DD_ONE(manager),DD_ZERO(manager));
+ if (var == NULL) return(NULL);
+ cuddRef(var);
+ res = cuddAddIteRecur(manager,var,T,E);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(manager,var);
+ Cudd_RecursiveDeref(manager, T);
+ Cudd_RecursiveDeref(manager, E);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(manager,var);
+ Cudd_RecursiveDeref(manager, T);
+ Cudd_RecursiveDeref(manager, E);
+
+ /* Do not keep the result if the reference count is only 1, since
+ ** it will not be visited again.
+ */
+ if (node->ref != 1) {
+ ptrint fanout = (ptrint) node->ref;
+ cuddSatDec(fanout);
+ if (!cuddHashTableInsert1(table,node,res,fanout)) {
+ Cudd_RecursiveDeref(manager, res);
+ return(NULL);
+ }
+ }
+ cuddDeref(res);
+ return(res);
+
+} /* end of cuddAddPermuteRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_bddPermute.]
+
+ Description [ Recursively puts the BDD in the order given in the array permut.
+ Checks for trivial cases to terminate recursion, then splits on the
+ children of this node. Once the solutions for the children are
+ obtained, it puts into the current position the node from the rest of
+ the BDD that should be here. Then returns this BDD.
+ The key here is that the node being visited is NOT put in its proper
+ place by this instance, but rather is switched when its proper position
+ is reached in the recursion tree.<p>
+ The DdNode * that is returned is the same BDD as passed in as node,
+ but in the new order.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddPermute cuddAddPermuteRecur]
+
+******************************************************************************/
+static DdNode *
+cuddBddPermuteRecur(
+ DdManager * manager /* DD manager */,
+ DdHashTable * table /* computed table */,
+ DdNode * node /* BDD to be reordered */,
+ int * permut /* permutation array */)
+{
+ DdNode *N,*T,*E;
+ DdNode *res;
+ int index;
+
+ statLine(manager);
+ N = Cudd_Regular(node);
+
+ /* Check for terminal case of constant node. */
+ if (cuddIsConstant(N)) {
+ return(node);
+ }
+
+ /* If problem already solved, look up answer and return. */
+ if (N->ref != 1 && (res = cuddHashTableLookup1(table,N)) != NULL) {
+#ifdef DD_DEBUG
+ bddPermuteRecurHits++;
+#endif
+ return(Cudd_NotCond(res,N != node));
+ }
+
+ /* Split and recur on children of this node. */
+ T = cuddBddPermuteRecur(manager,table,cuddT(N),permut);
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+ E = cuddBddPermuteRecur(manager,table,cuddE(N),permut);
+ if (E == NULL) {
+ Cudd_IterDerefBdd(manager, T);
+ return(NULL);
+ }
+ cuddRef(E);
+
+ /* Move variable that should be in this position to this position
+ ** by retrieving the single var BDD for that variable, and calling
+ ** cuddBddIteRecur with the T and E we just created.
+ */
+ index = permut[N->index];
+ res = cuddBddIteRecur(manager,manager->vars[index],T,E);
+ if (res == NULL) {
+ Cudd_IterDerefBdd(manager, T);
+ Cudd_IterDerefBdd(manager, E);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_IterDerefBdd(manager, T);
+ Cudd_IterDerefBdd(manager, E);
+
+ /* Do not keep the result if the reference count is only 1, since
+ ** it will not be visited again.
+ */
+ if (N->ref != 1) {
+ ptrint fanout = (ptrint) N->ref;
+ cuddSatDec(fanout);
+ if (!cuddHashTableInsert1(table,N,res,fanout)) {
+ Cudd_IterDerefBdd(manager, res);
+ return(NULL);
+ }
+ }
+ cuddDeref(res);
+ return(Cudd_NotCond(res,N != node));
+
+} /* end of cuddBddPermuteRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_bddVarMap.]
+
+ Description [Implements the recursive step of Cudd_bddVarMap.
+ Returns a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddVarMap]
+
+******************************************************************************/
+static DdNode *
+cuddBddVarMapRecur(
+ DdManager *manager /* DD manager */,
+ DdNode *f /* BDD to be remapped */)
+{
+ DdNode *F, *T, *E;
+ DdNode *res;
+ int index;
+
+ statLine(manager);
+ F = Cudd_Regular(f);
+
+ /* Check for terminal case of constant node. */
+ if (cuddIsConstant(F)) {
+ return(f);
+ }
+
+ /* If problem already solved, look up answer and return. */
+ if (F->ref != 1 &&
+ (res = cuddCacheLookup1(manager,Cudd_bddVarMap,F)) != NULL) {
+ return(Cudd_NotCond(res,F != f));
+ }
+
+ /* Split and recur on children of this node. */
+ T = cuddBddVarMapRecur(manager,cuddT(F));
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+ E = cuddBddVarMapRecur(manager,cuddE(F));
+ if (E == NULL) {
+ Cudd_IterDerefBdd(manager, T);
+ return(NULL);
+ }
+ cuddRef(E);
+
+ /* Move variable that should be in this position to this position
+ ** by retrieving the single var BDD for that variable, and calling
+ ** cuddBddIteRecur with the T and E we just created.
+ */
+ index = manager->map[F->index];
+ res = cuddBddIteRecur(manager,manager->vars[index],T,E);
+ if (res == NULL) {
+ Cudd_IterDerefBdd(manager, T);
+ Cudd_IterDerefBdd(manager, E);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_IterDerefBdd(manager, T);
+ Cudd_IterDerefBdd(manager, E);
+
+ /* Do not keep the result if the reference count is only 1, since
+ ** it will not be visited again.
+ */
+ if (F->ref != 1) {
+ cuddCacheInsert1(manager,Cudd_bddVarMap,F,res);
+ }
+ cuddDeref(res);
+ return(Cudd_NotCond(res,F != f));
+
+} /* end of cuddBddVarMapRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addVectorCompose.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+cuddAddVectorComposeRecur(
+ DdManager * dd /* DD manager */,
+ DdHashTable * table /* computed table */,
+ DdNode * f /* ADD in which to compose */,
+ DdNode ** vector /* functions to substitute */,
+ int deepest /* depth of deepest substitution */)
+{
+ DdNode *T,*E;
+ DdNode *res;
+
+ statLine(dd);
+ /* If we are past the deepest substitution, return f. */
+ if (cuddI(dd,f->index) > deepest) {
+ return(f);
+ }
+
+ if ((res = cuddHashTableLookup1(table,f)) != NULL) {
+#ifdef DD_DEBUG
+ addVectorComposeHits++;
+#endif
+ return(res);
+ }
+
+ /* Split and recur on children of this node. */
+ T = cuddAddVectorComposeRecur(dd,table,cuddT(f),vector,deepest);
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+ E = cuddAddVectorComposeRecur(dd,table,cuddE(f),vector,deepest);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ return(NULL);
+ }
+ cuddRef(E);
+
+ /* Retrieve the 0-1 ADD for the current top variable and call
+ ** cuddAddIteRecur with the T and E we just created.
+ */
+ res = cuddAddIteRecur(dd,vector[f->index],T,E);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+
+ /* Do not keep the result if the reference count is only 1, since
+ ** it will not be visited again
+ */
+ if (f->ref != 1) {
+ ptrint fanout = (ptrint) f->ref;
+ cuddSatDec(fanout);
+ if (!cuddHashTableInsert1(table,f,res,fanout)) {
+ Cudd_RecursiveDeref(dd, res);
+ return(NULL);
+ }
+ }
+ cuddDeref(res);
+ return(res);
+
+} /* end of cuddAddVectorComposeRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addGeneralVectorCompose.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+cuddAddGeneralVectorComposeRecur(
+ DdManager * dd /* DD manager */,
+ DdHashTable * table /* computed table */,
+ DdNode * f /* ADD in which to compose */,
+ DdNode ** vectorOn /* functions to substitute for x_i */,
+ DdNode ** vectorOff /* functions to substitute for x_i' */,
+ int deepest /* depth of deepest substitution */)
+{
+ DdNode *T,*E,*t,*e;
+ DdNode *res;
+
+ /* If we are past the deepest substitution, return f. */
+ if (cuddI(dd,f->index) > deepest) {
+ return(f);
+ }
+
+ if ((res = cuddHashTableLookup1(table,f)) != NULL) {
+#ifdef DD_DEBUG
+ addGeneralVectorComposeHits++;
+#endif
+ return(res);
+ }
+
+ /* Split and recur on children of this node. */
+ T = cuddAddGeneralVectorComposeRecur(dd,table,cuddT(f),
+ vectorOn,vectorOff,deepest);
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+ E = cuddAddGeneralVectorComposeRecur(dd,table,cuddE(f),
+ vectorOn,vectorOff,deepest);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd, T);
+ return(NULL);
+ }
+ cuddRef(E);
+
+ /* Retrieve the compose ADDs for the current top variable and call
+ ** cuddAddApplyRecur with the T and E we just created.
+ */
+ t = cuddAddApplyRecur(dd,Cudd_addTimes,vectorOn[f->index],T);
+ if (t == NULL) {
+ Cudd_RecursiveDeref(dd,T);
+ Cudd_RecursiveDeref(dd,E);
+ return(NULL);
+ }
+ cuddRef(t);
+ e = cuddAddApplyRecur(dd,Cudd_addTimes,vectorOff[f->index],E);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(dd,T);
+ Cudd_RecursiveDeref(dd,E);
+ Cudd_RecursiveDeref(dd,t);
+ return(NULL);
+ }
+ cuddRef(e);
+ res = cuddAddApplyRecur(dd,Cudd_addPlus,t,e);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd,T);
+ Cudd_RecursiveDeref(dd,E);
+ Cudd_RecursiveDeref(dd,t);
+ Cudd_RecursiveDeref(dd,e);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd,T);
+ Cudd_RecursiveDeref(dd,E);
+ Cudd_RecursiveDeref(dd,t);
+ Cudd_RecursiveDeref(dd,e);
+
+ /* Do not keep the result if the reference count is only 1, since
+ ** it will not be visited again
+ */
+ if (f->ref != 1) {
+ ptrint fanout = (ptrint) f->ref;
+ cuddSatDec(fanout);
+ if (!cuddHashTableInsert1(table,f,res,fanout)) {
+ Cudd_RecursiveDeref(dd, res);
+ return(NULL);
+ }
+ }
+ cuddDeref(res);
+ return(res);
+
+} /* end of cuddAddGeneralVectorComposeRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addNonSimCompose.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+cuddAddNonSimComposeRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode ** vector,
+ DdNode * key,
+ DdNode * cube,
+ int lastsub)
+{
+ DdNode *f1, *f0, *key1, *key0, *cube1, *var;
+ DdNode *T,*E;
+ DdNode *r;
+ unsigned int top, topf, topk, topc;
+ unsigned int index;
+ int i;
+ DdNode **vect1;
+ DdNode **vect0;
+
+ statLine(dd);
+ /* If we are past the deepest substitution, return f. */
+ if (cube == DD_ONE(dd) || cuddIsConstant(f)) {
+ return(f);
+ }
+
+ /* If problem already solved, look up answer and return. */
+ r = cuddCacheLookup(dd,DD_ADD_NON_SIM_COMPOSE_TAG,f,key,cube);
+ if (r != NULL) {
+ return(r);
+ }
+
+ /* Find top variable. we just need to look at f, key, and cube,
+ ** because all the varibles in the gi are in key.
+ */
+ topf = cuddI(dd,f->index);
+ topk = cuddI(dd,key->index);
+ top = ddMin(topf,topk);
+ topc = cuddI(dd,cube->index);
+ top = ddMin(top,topc);
+ index = dd->invperm[top];
+
+ /* Compute the cofactors. */
+ if (topf == top) {
+ f1 = cuddT(f);
+ f0 = cuddE(f);
+ } else {
+ f1 = f0 = f;
+ }
+ if (topc == top) {
+ cube1 = cuddT(cube);
+ /* We want to eliminate vector[index] from key. Otherwise
+ ** cache performance is severely affected. Hence we
+ ** existentially quantify the variable with index "index" from key.
+ */
+ var = Cudd_addIthVar(dd, (int) index);
+ if (var == NULL) {
+ return(NULL);
+ }
+ cuddRef(var);
+ key1 = cuddAddExistAbstractRecur(dd, key, var);
+ if (key1 == NULL) {
+ Cudd_RecursiveDeref(dd,var);
+ return(NULL);
+ }
+ cuddRef(key1);
+ Cudd_RecursiveDeref(dd,var);
+ key0 = key1;
+ } else {
+ cube1 = cube;
+ if (topk == top) {
+ key1 = cuddT(key);
+ key0 = cuddE(key);
+ } else {
+ key1 = key0 = key;
+ }
+ cuddRef(key1);
+ }
+
+ /* Allocate two new vectors for the cofactors of vector. */
+ vect1 = ALLOC(DdNode *,lastsub);
+ if (vect1 == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd,key1);
+ return(NULL);
+ }
+ vect0 = ALLOC(DdNode *,lastsub);
+ if (vect0 == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd,key1);
+ FREE(vect1);
+ return(NULL);
+ }
+
+ /* Cofactor the gi. Eliminate vect1[index] and vect0[index], because
+ ** we do not need them.
+ */
+ for (i = 0; i < lastsub; i++) {
+ DdNode *gi = vector[i];
+ if (gi == NULL) {
+ vect1[i] = vect0[i] = NULL;
+ } else if (gi->index == index) {
+ vect1[i] = cuddT(gi);
+ vect0[i] = cuddE(gi);
+ } else {
+ vect1[i] = vect0[i] = gi;
+ }
+ }
+ vect1[index] = vect0[index] = NULL;
+
+ /* Recur on children. */
+ T = cuddAddNonSimComposeRecur(dd,f1,vect1,key1,cube1,lastsub);
+ FREE(vect1);
+ if (T == NULL) {
+ Cudd_RecursiveDeref(dd,key1);
+ FREE(vect0);
+ return(NULL);
+ }
+ cuddRef(T);
+ E = cuddAddNonSimComposeRecur(dd,f0,vect0,key0,cube1,lastsub);
+ FREE(vect0);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd,key1);
+ Cudd_RecursiveDeref(dd,T);
+ return(NULL);
+ }
+ cuddRef(E);
+ Cudd_RecursiveDeref(dd,key1);
+
+ /* Retrieve the 0-1 ADD for the current top variable from vector,
+ ** and call cuddAddIteRecur with the T and E we just created.
+ */
+ r = cuddAddIteRecur(dd,vector[index],T,E);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd,T);
+ Cudd_RecursiveDeref(dd,E);
+ return(NULL);
+ }
+ cuddRef(r);
+ Cudd_RecursiveDeref(dd,T);
+ Cudd_RecursiveDeref(dd,E);
+ cuddDeref(r);
+
+ /* Store answer to trim recursion. */
+ cuddCacheInsert(dd,DD_ADD_NON_SIM_COMPOSE_TAG,f,key,cube,r);
+
+ return(r);
+
+} /* end of cuddAddNonSimComposeRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddVectorCompose.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+cuddBddVectorComposeRecur(
+ DdManager * dd /* DD manager */,
+ DdHashTable * table /* computed table */,
+ DdNode * f /* BDD in which to compose */,
+ DdNode ** vector /* functions to be composed */,
+ int deepest /* depth of the deepest substitution */)
+{
+ DdNode *F,*T,*E;
+ DdNode *res;
+
+ statLine(dd);
+ F = Cudd_Regular(f);
+
+ /* If we are past the deepest substitution, return f. */
+ if (cuddI(dd,F->index) > deepest) {
+ return(f);
+ }
+
+ /* If problem already solved, look up answer and return. */
+ if ((res = cuddHashTableLookup1(table,F)) != NULL) {
+#ifdef DD_DEBUG
+ bddVectorComposeHits++;
+#endif
+ return(Cudd_NotCond(res,F != f));
+ }
+
+ /* Split and recur on children of this node. */
+ T = cuddBddVectorComposeRecur(dd,table,cuddT(F),vector, deepest);
+ if (T == NULL) return(NULL);
+ cuddRef(T);
+ E = cuddBddVectorComposeRecur(dd,table,cuddE(F),vector, deepest);
+ if (E == NULL) {
+ Cudd_IterDerefBdd(dd, T);
+ return(NULL);
+ }
+ cuddRef(E);
+
+ /* Call cuddBddIteRecur with the BDD that replaces the current top
+ ** variable and the T and E we just created.
+ */
+ res = cuddBddIteRecur(dd,vector[F->index],T,E);
+ if (res == NULL) {
+ Cudd_IterDerefBdd(dd, T);
+ Cudd_IterDerefBdd(dd, E);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_IterDerefBdd(dd, T);
+ Cudd_IterDerefBdd(dd, E);
+
+ /* Do not keep the result if the reference count is only 1, since
+ ** it will not be visited again.
+ */
+ if (F->ref != 1) {
+ ptrint fanout = (ptrint) F->ref;
+ cuddSatDec(fanout);
+ if (!cuddHashTableInsert1(table,F,res,fanout)) {
+ Cudd_IterDerefBdd(dd, res);
+ return(NULL);
+ }
+ }
+ cuddDeref(res);
+ return(Cudd_NotCond(res,F != f));
+
+} /* end of cuddBddVectorComposeRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Comparison of a function to the i-th ADD variable.]
+
+ Description [Comparison of a function to the i-th ADD variable. Returns 1 if
+ the function is the i-th ADD variable; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DD_INLINE
+static int
+ddIsIthAddVar(
+ DdManager * dd,
+ DdNode * f,
+ unsigned int i)
+{
+ return(f->index == i && cuddT(f) == DD_ONE(dd) && cuddE(f) == DD_ZERO(dd));
+
+} /* end of ddIsIthAddVar */
+
+
+/**Function********************************************************************
+
+ Synopsis [Comparison of a pair of functions to the i-th ADD variable.]
+
+ Description [Comparison of a pair of functions to the i-th ADD
+ variable. Returns 1 if the functions are the i-th ADD variable and its
+ complement; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DD_INLINE
+static int
+ddIsIthAddVarPair(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ unsigned int i)
+{
+ return(f->index == i && g->index == i &&
+ cuddT(f) == DD_ONE(dd) && cuddE(f) == DD_ZERO(dd) &&
+ cuddT(g) == DD_ZERO(dd) && cuddE(g) == DD_ONE(dd));
+
+} /* end of ddIsIthAddVarPair */
diff --git a/src/bdd/cudd/cuddDecomp.c b/src/bdd/cudd/cuddDecomp.c
new file mode 100644
index 00000000..d9c28482
--- /dev/null
+++ b/src/bdd/cudd/cuddDecomp.c
@@ -0,0 +1,2150 @@
+/**CFile***********************************************************************
+
+ FileName [cuddDecomp.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions for BDD decomposition.]
+
+ Description [External procedures included in this file:
+ <ul>
+ <li> Cudd_bddApproxConjDecomp()
+ <li> Cudd_bddApproxDisjDecomp()
+ <li> Cudd_bddIterConjDecomp()
+ <li> Cudd_bddIterDisjDecomp()
+ <li> Cudd_bddGenConjDecomp()
+ <li> Cudd_bddGenDisjDecomp()
+ <li> Cudd_bddVarConjDecomp()
+ <li> Cudd_bddVarDisjDecomp()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> cuddConjunctsAux()
+ <li> CreateBotDist()
+ <li> BuildConjuncts()
+ <li> ConjunctsFree()
+ </ul>]
+
+ Author [Kavita Ravi, Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+#define DEPTH 5
+#define THRESHOLD 10
+#define NONE 0
+#define PAIR_ST 1
+#define PAIR_CR 2
+#define G_ST 3
+#define G_CR 4
+#define H_ST 5
+#define H_CR 6
+#define BOTH_G 7
+#define BOTH_H 8
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+typedef struct Conjuncts {
+ DdNode *g;
+ DdNode *h;
+} Conjuncts;
+
+typedef struct NodeStat {
+ int distance;
+ int localRef;
+} NodeStat;
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddDecomp.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+static DdNode *one, *zero;
+long lastTimeG;
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+#define FactorsNotStored(factors) ((int)((long)(factors) & 01))
+
+#define FactorsComplement(factors) ((Conjuncts *)((long)(factors) | 01))
+
+#define FactorsUncomplement(factors) ((Conjuncts *)((long)(factors) ^ 01))
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static NodeStat * CreateBotDist ARGS((DdNode * node, st_table * distanceTable));
+static double CountMinterms ARGS((DdNode * node, double max, st_table * mintermTable, FILE *fp));
+static void ConjunctsFree ARGS((DdManager * dd, Conjuncts * factors));
+static int PairInTables ARGS((DdNode * g, DdNode * h, st_table * ghTable));
+static Conjuncts * CheckTablesCacheAndReturn ARGS((DdNode * node, DdNode * g, DdNode * h, st_table * ghTable, st_table * cacheTable));
+static Conjuncts * PickOnePair ARGS((DdNode * node, DdNode * g1, DdNode * h1, DdNode * g2, DdNode * h2, st_table * ghTable, st_table * cacheTable));
+static Conjuncts * CheckInTables ARGS((DdNode * node, DdNode * g1, DdNode * h1, DdNode * g2, DdNode * h2, st_table * ghTable, st_table * cacheTable, int * outOfMem));
+static Conjuncts * ZeroCase ARGS((DdManager * dd, DdNode * node, Conjuncts * factorsNv, st_table * ghTable, st_table * cacheTable, int switched));
+static Conjuncts * BuildConjuncts ARGS((DdManager * dd, DdNode * node, st_table * distanceTable, st_table * cacheTable, int approxDistance, int maxLocalRef, st_table * ghTable, st_table * mintermTable));
+static int cuddConjunctsAux ARGS((DdManager * dd, DdNode * f, DdNode ** c1, DdNode ** c2));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs two-way conjunctive decomposition of a BDD.]
+
+ Description [Performs two-way conjunctive decomposition of a
+ BDD. This procedure owes its name to the use of supersetting to
+ obtain an initial factor of the given function. Returns the number
+ of conjuncts produced, that is, 2 if successful; 1 if no meaningful
+ decomposition was found; 0 otherwise. The conjuncts produced by this
+ procedure tend to be imbalanced.]
+
+ SideEffects [The factors are returned in an array as side effects.
+ The array is allocated by this function. It is the caller's responsibility
+ to free it. On successful completion, the conjuncts are already
+ referenced. If the function returns 0, the array for the conjuncts is
+ not allocated. If the function returns 1, the only factor equals the
+ function to be decomposed.]
+
+ SeeAlso [Cudd_bddApproxDisjDecomp Cudd_bddIterConjDecomp
+ Cudd_bddGenConjDecomp Cudd_bddVarConjDecomp Cudd_RemapOverApprox
+ Cudd_bddSqueeze Cudd_bddLICompaction]
+
+******************************************************************************/
+int
+Cudd_bddApproxConjDecomp(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be decomposed */,
+ DdNode *** conjuncts /* address of the first factor */)
+{
+ DdNode *superset1, *superset2, *glocal, *hlocal;
+ int nvars = Cudd_SupportSize(dd,f);
+
+ /* Find a tentative first factor by overapproximation and minimization. */
+ superset1 = Cudd_RemapOverApprox(dd,f,nvars,0,1.0);
+ if (superset1 == NULL) return(0);
+ cuddRef(superset1);
+ superset2 = Cudd_bddSqueeze(dd,f,superset1);
+ if (superset2 == NULL) {
+ Cudd_RecursiveDeref(dd,superset1);
+ return(0);
+ }
+ cuddRef(superset2);
+ Cudd_RecursiveDeref(dd,superset1);
+
+ /* Compute the second factor by minimization. */
+ hlocal = Cudd_bddLICompaction(dd,f,superset2);
+ if (hlocal == NULL) {
+ Cudd_RecursiveDeref(dd,superset2);
+ return(0);
+ }
+ cuddRef(hlocal);
+
+ /* Refine the first factor by minimization. If h turns out to be f, this
+ ** step guarantees that g will be 1. */
+ glocal = Cudd_bddLICompaction(dd,superset2,hlocal);
+ if (glocal == NULL) {
+ Cudd_RecursiveDeref(dd,superset2);
+ Cudd_RecursiveDeref(dd,hlocal);
+ return(0);
+ }
+ cuddRef(glocal);
+ Cudd_RecursiveDeref(dd,superset2);
+
+ if (glocal != DD_ONE(dd)) {
+ if (hlocal != DD_ONE(dd)) {
+ *conjuncts = ALLOC(DdNode *,2);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,glocal);
+ Cudd_RecursiveDeref(dd,hlocal);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = glocal;
+ (*conjuncts)[1] = hlocal;
+ return(2);
+ } else {
+ Cudd_RecursiveDeref(dd,hlocal);
+ *conjuncts = ALLOC(DdNode *,1);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,glocal);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = glocal;
+ return(1);
+ }
+ } else {
+ Cudd_RecursiveDeref(dd,glocal);
+ *conjuncts = ALLOC(DdNode *,1);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,hlocal);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = hlocal;
+ return(1);
+ }
+
+} /* end of Cudd_bddApproxConjDecomp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs two-way disjunctive decomposition of a BDD.]
+
+ Description [Performs two-way disjunctive decomposition of a BDD.
+ Returns the number of disjuncts produced, that is, 2 if successful;
+ 1 if no meaningful decomposition was found; 0 otherwise. The
+ disjuncts produced by this procedure tend to be imbalanced.]
+
+ SideEffects [The two disjuncts are returned in an array as side effects.
+ The array is allocated by this function. It is the caller's responsibility
+ to free it. On successful completion, the disjuncts are already
+ referenced. If the function returns 0, the array for the disjuncts is
+ not allocated. If the function returns 1, the only factor equals the
+ function to be decomposed.]
+
+ SeeAlso [Cudd_bddApproxConjDecomp Cudd_bddIterDisjDecomp
+ Cudd_bddGenDisjDecomp Cudd_bddVarDisjDecomp]
+
+******************************************************************************/
+int
+Cudd_bddApproxDisjDecomp(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be decomposed */,
+ DdNode *** disjuncts /* address of the array of the disjuncts */)
+{
+ int result, i;
+
+ result = Cudd_bddApproxConjDecomp(dd,Cudd_Not(f),disjuncts);
+ for (i = 0; i < result; i++) {
+ (*disjuncts)[i] = Cudd_Not((*disjuncts)[i]);
+ }
+ return(result);
+
+} /* end of Cudd_bddApproxDisjDecomp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs two-way conjunctive decomposition of a BDD.]
+
+ Description [Performs two-way conjunctive decomposition of a
+ BDD. This procedure owes its name to the iterated use of
+ supersetting to obtain a factor of the given function. Returns the
+ number of conjuncts produced, that is, 2 if successful; 1 if no
+ meaningful decomposition was found; 0 otherwise. The conjuncts
+ produced by this procedure tend to be imbalanced.]
+
+ SideEffects [The factors are returned in an array as side effects.
+ The array is allocated by this function. It is the caller's responsibility
+ to free it. On successful completion, the conjuncts are already
+ referenced. If the function returns 0, the array for the conjuncts is
+ not allocated. If the function returns 1, the only factor equals the
+ function to be decomposed.]
+
+ SeeAlso [Cudd_bddIterDisjDecomp Cudd_bddApproxConjDecomp
+ Cudd_bddGenConjDecomp Cudd_bddVarConjDecomp Cudd_RemapOverApprox
+ Cudd_bddSqueeze Cudd_bddLICompaction]
+
+******************************************************************************/
+int
+Cudd_bddIterConjDecomp(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be decomposed */,
+ DdNode *** conjuncts /* address of the array of conjuncts */)
+{
+ DdNode *superset1, *superset2, *old[2], *res[2];
+ int sizeOld, sizeNew;
+ int nvars = Cudd_SupportSize(dd,f);
+
+ old[0] = DD_ONE(dd);
+ cuddRef(old[0]);
+ old[1] = f;
+ cuddRef(old[1]);
+ sizeOld = Cudd_SharingSize(old,2);
+
+ do {
+ /* Find a tentative first factor by overapproximation and
+ ** minimization. */
+ superset1 = Cudd_RemapOverApprox(dd,old[1],nvars,0,1.0);
+ if (superset1 == NULL) {
+ Cudd_RecursiveDeref(dd,old[0]);
+ Cudd_RecursiveDeref(dd,old[1]);
+ return(0);
+ }
+ cuddRef(superset1);
+ superset2 = Cudd_bddSqueeze(dd,old[1],superset1);
+ if (superset2 == NULL) {
+ Cudd_RecursiveDeref(dd,old[0]);
+ Cudd_RecursiveDeref(dd,old[1]);
+ Cudd_RecursiveDeref(dd,superset1);
+ return(0);
+ }
+ cuddRef(superset2);
+ Cudd_RecursiveDeref(dd,superset1);
+ res[0] = Cudd_bddAnd(dd,old[0],superset2);
+ if (res[0] == NULL) {
+ Cudd_RecursiveDeref(dd,superset2);
+ Cudd_RecursiveDeref(dd,old[0]);
+ Cudd_RecursiveDeref(dd,old[1]);
+ return(0);
+ }
+ cuddRef(res[0]);
+ Cudd_RecursiveDeref(dd,superset2);
+ if (res[0] == old[0]) {
+ Cudd_RecursiveDeref(dd,res[0]);
+ break; /* avoid infinite loop */
+ }
+
+ /* Compute the second factor by minimization. */
+ res[1] = Cudd_bddLICompaction(dd,old[1],res[0]);
+ if (res[1] == NULL) {
+ Cudd_RecursiveDeref(dd,old[0]);
+ Cudd_RecursiveDeref(dd,old[1]);
+ return(0);
+ }
+ cuddRef(res[1]);
+
+ sizeNew = Cudd_SharingSize(res,2);
+ if (sizeNew <= sizeOld) {
+ Cudd_RecursiveDeref(dd,old[0]);
+ old[0] = res[0];
+ Cudd_RecursiveDeref(dd,old[1]);
+ old[1] = res[1];
+ sizeOld = sizeNew;
+ } else {
+ Cudd_RecursiveDeref(dd,res[0]);
+ Cudd_RecursiveDeref(dd,res[1]);
+ break;
+ }
+
+ } while (1);
+
+ /* Refine the first factor by minimization. If h turns out to
+ ** be f, this step guarantees that g will be 1. */
+ superset1 = Cudd_bddLICompaction(dd,old[0],old[1]);
+ if (superset1 == NULL) {
+ Cudd_RecursiveDeref(dd,old[0]);
+ Cudd_RecursiveDeref(dd,old[1]);
+ return(0);
+ }
+ cuddRef(superset1);
+ Cudd_RecursiveDeref(dd,old[0]);
+ old[0] = superset1;
+
+ if (old[0] != DD_ONE(dd)) {
+ if (old[1] != DD_ONE(dd)) {
+ *conjuncts = ALLOC(DdNode *,2);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,old[0]);
+ Cudd_RecursiveDeref(dd,old[1]);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = old[0];
+ (*conjuncts)[1] = old[1];
+ return(2);
+ } else {
+ Cudd_RecursiveDeref(dd,old[1]);
+ *conjuncts = ALLOC(DdNode *,1);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,old[0]);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = old[0];
+ return(1);
+ }
+ } else {
+ Cudd_RecursiveDeref(dd,old[0]);
+ *conjuncts = ALLOC(DdNode *,1);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,old[1]);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = old[1];
+ return(1);
+ }
+
+} /* end of Cudd_bddIterConjDecomp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs two-way disjunctive decomposition of a BDD.]
+
+ Description [Performs two-way disjunctive decomposition of a BDD.
+ Returns the number of disjuncts produced, that is, 2 if successful;
+ 1 if no meaningful decomposition was found; 0 otherwise. The
+ disjuncts produced by this procedure tend to be imbalanced.]
+
+ SideEffects [The two disjuncts are returned in an array as side effects.
+ The array is allocated by this function. It is the caller's responsibility
+ to free it. On successful completion, the disjuncts are already
+ referenced. If the function returns 0, the array for the disjuncts is
+ not allocated. If the function returns 1, the only factor equals the
+ function to be decomposed.]
+
+ SeeAlso [Cudd_bddIterConjDecomp Cudd_bddApproxDisjDecomp
+ Cudd_bddGenDisjDecomp Cudd_bddVarDisjDecomp]
+
+******************************************************************************/
+int
+Cudd_bddIterDisjDecomp(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be decomposed */,
+ DdNode *** disjuncts /* address of the array of the disjuncts */)
+{
+ int result, i;
+
+ result = Cudd_bddIterConjDecomp(dd,Cudd_Not(f),disjuncts);
+ for (i = 0; i < result; i++) {
+ (*disjuncts)[i] = Cudd_Not((*disjuncts)[i]);
+ }
+ return(result);
+
+} /* end of Cudd_bddIterDisjDecomp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs two-way conjunctive decomposition of a BDD.]
+
+ Description [Performs two-way conjunctive decomposition of a
+ BDD. This procedure owes its name to the fact tht it generalizes the
+ decomposition based on the cofactors with respect to one
+ variable. Returns the number of conjuncts produced, that is, 2 if
+ successful; 1 if no meaningful decomposition was found; 0
+ otherwise. The conjuncts produced by this procedure tend to be
+ balanced.]
+
+ SideEffects [The two factors are returned in an array as side effects.
+ The array is allocated by this function. It is the caller's responsibility
+ to free it. On successful completion, the conjuncts are already
+ referenced. If the function returns 0, the array for the conjuncts is
+ not allocated. If the function returns 1, the only factor equals the
+ function to be decomposed.]
+
+ SeeAlso [Cudd_bddGenDisjDecomp Cudd_bddApproxConjDecomp
+ Cudd_bddIterConjDecomp Cudd_bddVarConjDecomp]
+
+******************************************************************************/
+int
+Cudd_bddGenConjDecomp(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be decomposed */,
+ DdNode *** conjuncts /* address of the array of conjuncts */)
+{
+ int result;
+ DdNode *glocal, *hlocal;
+
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+
+ do {
+ dd->reordered = 0;
+ result = cuddConjunctsAux(dd, f, &glocal, &hlocal);
+ } while (dd->reordered == 1);
+
+ if (result == 0) {
+ return(0);
+ }
+
+ if (glocal != one) {
+ if (hlocal != one) {
+ *conjuncts = ALLOC(DdNode *,2);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,glocal);
+ Cudd_RecursiveDeref(dd,hlocal);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = glocal;
+ (*conjuncts)[1] = hlocal;
+ return(2);
+ } else {
+ Cudd_RecursiveDeref(dd,hlocal);
+ *conjuncts = ALLOC(DdNode *,1);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,glocal);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = glocal;
+ return(1);
+ }
+ } else {
+ Cudd_RecursiveDeref(dd,glocal);
+ *conjuncts = ALLOC(DdNode *,1);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,hlocal);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = hlocal;
+ return(1);
+ }
+
+} /* end of Cudd_bddGenConjDecomp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs two-way disjunctive decomposition of a BDD.]
+
+ Description [Performs two-way disjunctive decomposition of a BDD.
+ Returns the number of disjuncts produced, that is, 2 if successful;
+ 1 if no meaningful decomposition was found; 0 otherwise. The
+ disjuncts produced by this procedure tend to be balanced.]
+
+ SideEffects [The two disjuncts are returned in an array as side effects.
+ The array is allocated by this function. It is the caller's responsibility
+ to free it. On successful completion, the disjuncts are already
+ referenced. If the function returns 0, the array for the disjuncts is
+ not allocated. If the function returns 1, the only factor equals the
+ function to be decomposed.]
+
+ SeeAlso [Cudd_bddGenConjDecomp Cudd_bddApproxDisjDecomp
+ Cudd_bddIterDisjDecomp Cudd_bddVarDisjDecomp]
+
+******************************************************************************/
+int
+Cudd_bddGenDisjDecomp(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be decomposed */,
+ DdNode *** disjuncts /* address of the array of the disjuncts */)
+{
+ int result, i;
+
+ result = Cudd_bddGenConjDecomp(dd,Cudd_Not(f),disjuncts);
+ for (i = 0; i < result; i++) {
+ (*disjuncts)[i] = Cudd_Not((*disjuncts)[i]);
+ }
+ return(result);
+
+} /* end of Cudd_bddGenDisjDecomp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs two-way conjunctive decomposition of a BDD.]
+
+ Description [Conjunctively decomposes one BDD according to a
+ variable. If <code>f</code> is the function of the BDD and
+ <code>x</code> is the variable, the decomposition is
+ <code>(f+x)(f+x')</code>. The variable is chosen so as to balance
+ the sizes of the two conjuncts and to keep them small. Returns the
+ number of conjuncts produced, that is, 2 if successful; 1 if no
+ meaningful decomposition was found; 0 otherwise.]
+
+ SideEffects [The two factors are returned in an array as side effects.
+ The array is allocated by this function. It is the caller's responsibility
+ to free it. On successful completion, the conjuncts are already
+ referenced. If the function returns 0, the array for the conjuncts is
+ not allocated. If the function returns 1, the only factor equals the
+ function to be decomposed.]
+
+ SeeAlso [Cudd_bddVarDisjDecomp Cudd_bddGenConjDecomp
+ Cudd_bddApproxConjDecomp Cudd_bddIterConjDecomp]
+
+*****************************************************************************/
+int
+Cudd_bddVarConjDecomp(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be decomposed */,
+ DdNode *** conjuncts /* address of the array of conjuncts */)
+{
+ int best;
+ int min;
+ DdNode *support, *scan, *var, *glocal, *hlocal;
+
+ /* Find best cofactoring variable. */
+ support = Cudd_Support(dd,f);
+ if (support == NULL) return(0);
+ if (Cudd_IsConstant(support)) {
+ *conjuncts = ALLOC(DdNode *,1);
+ if (*conjuncts == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = f;
+ cuddRef((*conjuncts)[0]);
+ return(1);
+ }
+ cuddRef(support);
+ min = 1000000000;
+ best = -1;
+ scan = support;
+ while (!Cudd_IsConstant(scan)) {
+ int i = scan->index;
+ int est1 = Cudd_EstimateCofactor(dd,f,i,1);
+ int est0 = Cudd_EstimateCofactor(dd,f,i,0);
+ /* Minimize the size of the larger of the two cofactors. */
+ int est = (est1 > est0) ? est1 : est0;
+ if (est < min) {
+ min = est;
+ best = i;
+ }
+ scan = cuddT(scan);
+ }
+#ifdef DD_DEBUG
+ assert(best >= 0 && best < dd->size);
+#endif
+ Cudd_RecursiveDeref(dd,support);
+
+ var = Cudd_bddIthVar(dd,best);
+ glocal = Cudd_bddOr(dd,f,var);
+ if (glocal == NULL) {
+ return(0);
+ }
+ cuddRef(glocal);
+ hlocal = Cudd_bddOr(dd,f,Cudd_Not(var));
+ if (hlocal == NULL) {
+ Cudd_RecursiveDeref(dd,glocal);
+ return(0);
+ }
+ cuddRef(hlocal);
+
+ if (glocal != DD_ONE(dd)) {
+ if (hlocal != DD_ONE(dd)) {
+ *conjuncts = ALLOC(DdNode *,2);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,glocal);
+ Cudd_RecursiveDeref(dd,hlocal);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = glocal;
+ (*conjuncts)[1] = hlocal;
+ return(2);
+ } else {
+ Cudd_RecursiveDeref(dd,hlocal);
+ *conjuncts = ALLOC(DdNode *,1);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,glocal);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = glocal;
+ return(1);
+ }
+ } else {
+ Cudd_RecursiveDeref(dd,glocal);
+ *conjuncts = ALLOC(DdNode *,1);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,hlocal);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = hlocal;
+ return(1);
+ }
+
+} /* end of Cudd_bddVarConjDecomp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs two-way disjunctive decomposition of a BDD.]
+
+ Description [Performs two-way disjunctive decomposition of a BDD
+ according to a variable. If <code>f</code> is the function of the
+ BDD and <code>x</code> is the variable, the decomposition is
+ <code>f*x + f*x'</code>. The variable is chosen so as to balance
+ the sizes of the two disjuncts and to keep them small. Returns the
+ number of disjuncts produced, that is, 2 if successful; 1 if no
+ meaningful decomposition was found; 0 otherwise.]
+
+ SideEffects [The two disjuncts are returned in an array as side effects.
+ The array is allocated by this function. It is the caller's responsibility
+ to free it. On successful completion, the disjuncts are already
+ referenced. If the function returns 0, the array for the disjuncts is
+ not allocated. If the function returns 1, the only factor equals the
+ function to be decomposed.]
+
+ SeeAlso [Cudd_bddVarConjDecomp Cudd_bddApproxDisjDecomp
+ Cudd_bddIterDisjDecomp Cudd_bddGenDisjDecomp]
+
+******************************************************************************/
+int
+Cudd_bddVarDisjDecomp(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be decomposed */,
+ DdNode *** disjuncts /* address of the array of the disjuncts */)
+{
+ int result, i;
+
+ result = Cudd_bddVarConjDecomp(dd,Cudd_Not(f),disjuncts);
+ for (i = 0; i < result; i++) {
+ (*disjuncts)[i] = Cudd_Not((*disjuncts)[i]);
+ }
+ return(result);
+
+} /* end of Cudd_bddVarDisjDecomp */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Get longest distance of node from constant.]
+
+ Description [Get longest distance of node from constant. Returns the
+ distance of the root from the constant if successful; CUDD_OUT_OF_MEM
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static NodeStat *
+CreateBotDist(
+ DdNode * node,
+ st_table * distanceTable)
+{
+ DdNode *N, *Nv, *Nnv;
+ int distance, distanceNv, distanceNnv;
+ NodeStat *nodeStat, *nodeStatNv, *nodeStatNnv;
+
+#if 0
+ if (Cudd_IsConstant(node)) {
+ return(0);
+ }
+#endif
+
+ /* Return the entry in the table if found. */
+ N = Cudd_Regular(node);
+ if (st_lookup(distanceTable, (char *)N, (char **)&nodeStat)) {
+ nodeStat->localRef++;
+ return(nodeStat);
+ }
+
+ Nv = cuddT(N);
+ Nnv = cuddE(N);
+ Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
+ Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));
+
+ /* Recur on the children. */
+ nodeStatNv = CreateBotDist(Nv, distanceTable);
+ if (nodeStatNv == NULL) return(NULL);
+ distanceNv = nodeStatNv->distance;
+
+ nodeStatNnv = CreateBotDist(Nnv, distanceTable);
+ if (nodeStatNnv == NULL) return(NULL);
+ distanceNnv = nodeStatNnv->distance;
+ /* Store max distance from constant; note sometimes this distance
+ ** may be to 0.
+ */
+ distance = (distanceNv > distanceNnv) ? (distanceNv+1) : (distanceNnv + 1);
+
+ nodeStat = ALLOC(NodeStat, 1);
+ if (nodeStat == NULL) {
+ return(0);
+ }
+ nodeStat->distance = distance;
+ nodeStat->localRef = 1;
+
+ if (st_insert(distanceTable, (char *)N, (char *)nodeStat) ==
+ ST_OUT_OF_MEM) {
+ return(0);
+
+ }
+ return(nodeStat);
+
+} /* end of CreateBotDist */
+
+
+/**Function********************************************************************
+
+ Synopsis [Count the number of minterms of each node ina a BDD and
+ store it in a hash table.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static double
+CountMinterms(
+ DdNode * node,
+ double max,
+ st_table * mintermTable,
+ FILE *fp)
+{
+ DdNode *N, *Nv, *Nnv;
+ double min, minNv, minNnv;
+ double *dummy;
+
+ N = Cudd_Regular(node);
+
+ if (cuddIsConstant(N)) {
+ if (node == zero) {
+ return(0);
+ } else {
+ return(max);
+ }
+ }
+
+ /* Return the entry in the table if found. */
+ if (st_lookup(mintermTable, (char *)node, (char **)&dummy)) {
+ min = *dummy;
+ return(min);
+ }
+
+ Nv = cuddT(N);
+ Nnv = cuddE(N);
+ Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
+ Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));
+
+ /* Recur on the children. */
+ minNv = CountMinterms(Nv, max, mintermTable, fp);
+ if (minNv == -1.0) return(-1.0);
+ minNnv = CountMinterms(Nnv, max, mintermTable, fp);
+ if (minNnv == -1.0) return(-1.0);
+ min = minNv / 2.0 + minNnv / 2.0;
+ /* store
+ */
+
+ dummy = ALLOC(double, 1);
+ if (dummy == NULL) return(-1.0);
+ *dummy = min;
+ if (st_insert(mintermTable, (char *)node, (char *)dummy) == ST_OUT_OF_MEM) {
+ (void) fprintf(fp, "st table insert failed\n");
+ }
+ return(min);
+
+} /* end of CountMinterms */
+
+
+/**Function********************************************************************
+
+ Synopsis [Free factors structure]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+ConjunctsFree(
+ DdManager * dd,
+ Conjuncts * factors)
+{
+ Cudd_RecursiveDeref(dd, factors->g);
+ Cudd_RecursiveDeref(dd, factors->h);
+ FREE(factors);
+ return;
+
+} /* end of ConjunctsFree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Check whether the given pair is in the tables.]
+
+ Description [.Check whether the given pair is in the tables. gTable
+ and hTable are combined.
+ absence in both is indicated by 0,
+ presence in gTable is indicated by 1,
+ presence in hTable by 2 and
+ presence in both by 3.
+ The values returned by this function are PAIR_ST,
+ PAIR_CR, G_ST, G_CR, H_ST, H_CR, BOTH_G, BOTH_H, NONE.
+ PAIR_ST implies g in gTable and h in hTable
+ PAIR_CR implies g in hTable and h in gTable
+ G_ST implies g in gTable and h not in any table
+ G_CR implies g in hTable and h not in any table
+ H_ST implies h in hTable and g not in any table
+ H_CR implies h in gTable and g not in any table
+ BOTH_G implies both in gTable
+ BOTH_H implies both in hTable
+ NONE implies none in table; ]
+
+ SideEffects []
+
+ SeeAlso [CheckTablesCacheAndReturn CheckInTables]
+
+******************************************************************************/
+static int
+PairInTables(
+ DdNode * g,
+ DdNode * h,
+ st_table * ghTable)
+{
+ int valueG, valueH, gPresent, hPresent;
+
+ valueG = valueH = gPresent = hPresent = 0;
+
+ gPresent = st_lookup_int(ghTable, (char *)Cudd_Regular(g), &valueG);
+ hPresent = st_lookup_int(ghTable, (char *)Cudd_Regular(h), &valueH);
+
+ if (!gPresent && !hPresent) return(NONE);
+
+ if (!hPresent) {
+ if (valueG & 1) return(G_ST);
+ if (valueG & 2) return(G_CR);
+ }
+ if (!gPresent) {
+ if (valueH & 1) return(H_CR);
+ if (valueH & 2) return(H_ST);
+ }
+ /* both in tables */
+ if ((valueG & 1) && (valueH & 2)) return(PAIR_ST);
+ if ((valueG & 2) && (valueH & 1)) return(PAIR_CR);
+
+ if (valueG & 1) {
+ return(BOTH_G);
+ } else {
+ return(BOTH_H);
+ }
+
+} /* end of PairInTables */
+
+
+/**Function********************************************************************
+
+ Synopsis [Check the tables for the existence of pair and return one
+ combination, cache the result.]
+
+ Description [Check the tables for the existence of pair and return
+ one combination, cache the result. The assumption is that one of the
+ conjuncts is already in the tables.]
+
+ SideEffects [g and h referenced for the cache]
+
+ SeeAlso [ZeroCase]
+
+******************************************************************************/
+static Conjuncts *
+CheckTablesCacheAndReturn(
+ DdNode * node,
+ DdNode * g,
+ DdNode * h,
+ st_table * ghTable,
+ st_table * cacheTable)
+{
+ int pairValue;
+ int value;
+ Conjuncts *factors;
+
+ value = 0;
+ /* check tables */
+ pairValue = PairInTables(g, h, ghTable);
+ assert(pairValue != NONE);
+ /* if both dont exist in table, we know one exists(either g or h).
+ * Therefore store the other and proceed
+ */
+ factors = ALLOC(Conjuncts, 1);
+ if (factors == NULL) return(NULL);
+ if ((pairValue == BOTH_H) || (pairValue == H_ST)) {
+ if (g != one) {
+ value = 0;
+ if (st_lookup_int(ghTable, (char *)Cudd_Regular(g), &value)) {
+ value |= 1;
+ } else {
+ value = 1;
+ }
+ if (st_insert(ghTable, (char *)Cudd_Regular(g),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ return(NULL);
+ }
+ }
+ factors->g = g;
+ factors->h = h;
+ } else if ((pairValue == BOTH_G) || (pairValue == G_ST)) {
+ if (h != one) {
+ value = 0;
+ if (st_lookup_int(ghTable, (char *)Cudd_Regular(h), &value)) {
+ value |= 2;
+ } else {
+ value = 2;
+ }
+ if (st_insert(ghTable, (char *)Cudd_Regular(h),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ return(NULL);
+ }
+ }
+ factors->g = g;
+ factors->h = h;
+ } else if (pairValue == H_CR) {
+ if (g != one) {
+ value = 2;
+ if (st_insert(ghTable, (char *)Cudd_Regular(g),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ return(NULL);
+ }
+ }
+ factors->g = h;
+ factors->h = g;
+ } else if (pairValue == G_CR) {
+ if (h != one) {
+ value = 1;
+ if (st_insert(ghTable, (char *)Cudd_Regular(h),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ return(NULL);
+ }
+ }
+ factors->g = h;
+ factors->h = g;
+ } else if (pairValue == PAIR_CR) {
+ /* pair exists in table */
+ factors->g = h;
+ factors->h = g;
+ } else if (pairValue == PAIR_ST) {
+ factors->g = g;
+ factors->h = h;
+ }
+
+ /* cache the result for this node */
+ if (st_insert(cacheTable, (char *)node, (char *)factors) == ST_OUT_OF_MEM) {
+ FREE(factors);
+ return(NULL);
+ }
+
+ return(factors);
+
+} /* end of CheckTablesCacheAndReturn */
+
+/**Function********************************************************************
+
+ Synopsis [Check the tables for the existence of pair and return one
+ combination, store in cache.]
+
+ Description [Check the tables for the existence of pair and return
+ one combination, store in cache. The pair that has more pointers to
+ it is picked. An approximation of the number of local pointers is
+ made by taking the reference count of the pairs sent. ]
+
+ SideEffects []
+
+ SeeAlso [ZeroCase BuildConjuncts]
+
+******************************************************************************/
+static Conjuncts *
+PickOnePair(
+ DdNode * node,
+ DdNode * g1,
+ DdNode * h1,
+ DdNode * g2,
+ DdNode * h2,
+ st_table * ghTable,
+ st_table * cacheTable)
+{
+ int value;
+ Conjuncts *factors;
+ int oneRef, twoRef;
+
+ factors = ALLOC(Conjuncts, 1);
+ if (factors == NULL) return(NULL);
+
+ /* count the number of pointers to pair 2 */
+ if (h2 == one) {
+ twoRef = (Cudd_Regular(g2))->ref;
+ } else if (g2 == one) {
+ twoRef = (Cudd_Regular(h2))->ref;
+ } else {
+ twoRef = ((Cudd_Regular(g2))->ref + (Cudd_Regular(h2))->ref)/2;
+ }
+
+ /* count the number of pointers to pair 1 */
+ if (h1 == one) {
+ oneRef = (Cudd_Regular(g1))->ref;
+ } else if (g1 == one) {
+ oneRef = (Cudd_Regular(h1))->ref;
+ } else {
+ oneRef = ((Cudd_Regular(g1))->ref + (Cudd_Regular(h1))->ref)/2;
+ }
+
+ /* pick the pair with higher reference count */
+ if (oneRef >= twoRef) {
+ factors->g = g1;
+ factors->h = h1;
+ } else {
+ factors->g = g2;
+ factors->h = h2;
+ }
+
+ /*
+ * Store computed factors in respective tables to encourage
+ * recombination.
+ */
+ if (factors->g != one) {
+ /* insert g in htable */
+ value = 0;
+ if (st_lookup_int(ghTable, (char *)Cudd_Regular(factors->g), &value)) {
+ if (value == 2) {
+ value |= 1;
+ if (st_insert(ghTable, (char *)Cudd_Regular(factors->g),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else {
+ value = 1;
+ if (st_insert(ghTable, (char *)Cudd_Regular(factors->g),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ }
+
+ if (factors->h != one) {
+ /* insert h in htable */
+ value = 0;
+ if (st_lookup_int(ghTable, (char *)Cudd_Regular(factors->h), &value)) {
+ if (value == 1) {
+ value |= 2;
+ if (st_insert(ghTable, (char *)Cudd_Regular(factors->h),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else {
+ value = 2;
+ if (st_insert(ghTable, (char *)Cudd_Regular(factors->h),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ }
+
+ /* Store factors in cache table for later use. */
+ if (st_insert(cacheTable, (char *)node, (char *)factors) ==
+ ST_OUT_OF_MEM) {
+ FREE(factors);
+ return(NULL);
+ }
+
+ return(factors);
+
+} /* end of PickOnePair */
+
+
+/**Function********************************************************************
+
+ Synopsis [Check if the two pairs exist in the table, If any of the
+ conjuncts do exist, store in the cache and return the corresponding pair.]
+
+ Description [Check if the two pairs exist in the table. If any of
+ the conjuncts do exist, store in the cache and return the
+ corresponding pair.]
+
+ SideEffects []
+
+ SeeAlso [ZeroCase BuildConjuncts]
+
+******************************************************************************/
+static Conjuncts *
+CheckInTables(
+ DdNode * node,
+ DdNode * g1,
+ DdNode * h1,
+ DdNode * g2,
+ DdNode * h2,
+ st_table * ghTable,
+ st_table * cacheTable,
+ int * outOfMem)
+{
+ int pairValue1, pairValue2;
+ Conjuncts *factors;
+ int value;
+
+ *outOfMem = 0;
+
+ /* check existence of pair in table */
+ pairValue1 = PairInTables(g1, h1, ghTable);
+ pairValue2 = PairInTables(g2, h2, ghTable);
+
+ /* if none of the 4 exist in the gh tables, return NULL */
+ if ((pairValue1 == NONE) && (pairValue2 == NONE)) {
+ return NULL;
+ }
+
+ factors = ALLOC(Conjuncts, 1);
+ if (factors == NULL) {
+ *outOfMem = 1;
+ return NULL;
+ }
+
+ /* pairs that already exist in the table get preference. */
+ if (pairValue1 == PAIR_ST) {
+ factors->g = g1;
+ factors->h = h1;
+ } else if (pairValue2 == PAIR_ST) {
+ factors->g = g2;
+ factors->h = h2;
+ } else if (pairValue1 == PAIR_CR) {
+ factors->g = h1;
+ factors->h = g1;
+ } else if (pairValue2 == PAIR_CR) {
+ factors->g = h2;
+ factors->h = g2;
+ } else if (pairValue1 == G_ST) {
+ /* g exists in the table, h is not found in either table */
+ factors->g = g1;
+ factors->h = h1;
+ if (h1 != one) {
+ value = 2;
+ if (st_insert(ghTable, (char *)Cudd_Regular(h1),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue1 == BOTH_G) {
+ /* g and h are found in the g table */
+ factors->g = g1;
+ factors->h = h1;
+ if (h1 != one) {
+ value = 3;
+ if (st_insert(ghTable, (char *)Cudd_Regular(h1),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue1 == H_ST) {
+ /* h exists in the table, g is not found in either table */
+ factors->g = g1;
+ factors->h = h1;
+ if (g1 != one) {
+ value = 1;
+ if (st_insert(ghTable, (char *)Cudd_Regular(g1),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue1 == BOTH_H) {
+ /* g and h are found in the h table */
+ factors->g = g1;
+ factors->h = h1;
+ if (g1 != one) {
+ value = 3;
+ if (st_insert(ghTable, (char *)Cudd_Regular(g1),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue2 == G_ST) {
+ /* g exists in the table, h is not found in either table */
+ factors->g = g2;
+ factors->h = h2;
+ if (h2 != one) {
+ value = 2;
+ if (st_insert(ghTable, (char *)Cudd_Regular(h2),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue2 == BOTH_G) {
+ /* g and h are found in the g table */
+ factors->g = g2;
+ factors->h = h2;
+ if (h2 != one) {
+ value = 3;
+ if (st_insert(ghTable, (char *)Cudd_Regular(h2),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue2 == H_ST) {
+ /* h exists in the table, g is not found in either table */
+ factors->g = g2;
+ factors->h = h2;
+ if (g2 != one) {
+ value = 1;
+ if (st_insert(ghTable, (char *)Cudd_Regular(g2),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue2 == BOTH_H) {
+ /* g and h are found in the h table */
+ factors->g = g2;
+ factors->h = h2;
+ if (g2 != one) {
+ value = 3;
+ if (st_insert(ghTable, (char *)Cudd_Regular(g2),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue1 == G_CR) {
+ /* g found in h table and h in none */
+ factors->g = h1;
+ factors->h = g1;
+ if (h1 != one) {
+ value = 1;
+ if (st_insert(ghTable, (char *)Cudd_Regular(h1),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue1 == H_CR) {
+ /* h found in g table and g in none */
+ factors->g = h1;
+ factors->h = g1;
+ if (g1 != one) {
+ value = 2;
+ if (st_insert(ghTable, (char *)Cudd_Regular(g1),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue2 == G_CR) {
+ /* g found in h table and h in none */
+ factors->g = h2;
+ factors->h = g2;
+ if (h2 != one) {
+ value = 1;
+ if (st_insert(ghTable, (char *)Cudd_Regular(h2),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue2 == H_CR) {
+ /* h found in g table and g in none */
+ factors->g = h2;
+ factors->h = g2;
+ if (g2 != one) {
+ value = 2;
+ if (st_insert(ghTable, (char *)Cudd_Regular(g2),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ }
+
+ /* Store factors in cache table for later use. */
+ if (st_insert(cacheTable, (char *)node, (char *)factors) ==
+ ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ return factors;
+} /* end of CheckInTables */
+
+
+
+/**Function********************************************************************
+
+ Synopsis [If one child is zero, do explicitly what Restrict does or better]
+
+ Description [If one child is zero, do explicitly what Restrict does or better.
+ First separate a variable and its child in the base case. In case of a cube
+ times a function, separate the cube and function. As a last resort, look in
+ tables.]
+
+ SideEffects [Frees the BDDs in factorsNv. factorsNv itself is not freed
+ because it is freed above.]
+
+ SeeAlso [BuildConjuncts]
+
+******************************************************************************/
+static Conjuncts *
+ZeroCase(
+ DdManager * dd,
+ DdNode * node,
+ Conjuncts * factorsNv,
+ st_table * ghTable,
+ st_table * cacheTable,
+ int switched)
+{
+ int topid;
+ DdNode *g, *h, *g1, *g2, *h1, *h2, *x, *N, *G, *H, *Gv, *Gnv;
+ DdNode *Hv, *Hnv;
+ int value;
+ int outOfMem;
+ Conjuncts *factors;
+
+ /* get var at this node */
+ N = Cudd_Regular(node);
+ topid = N->index;
+ x = dd->vars[topid];
+ x = (switched) ? Cudd_Not(x): x;
+ cuddRef(x);
+
+ /* Seprate variable and child */
+ if (factorsNv->g == one) {
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ factors = ALLOC(Conjuncts, 1);
+ if (factors == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ Cudd_RecursiveDeref(dd, x);
+ return(NULL);
+ }
+ factors->g = x;
+ factors->h = factorsNv->h;
+ /* cache the result*/
+ if (st_insert(cacheTable, (char *)node, (char *)factors) == ST_OUT_OF_MEM) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ Cudd_RecursiveDeref(dd, x);
+ FREE(factors);
+ return NULL;
+ }
+
+ /* store x in g table, the other node is already in the table */
+ if (st_lookup_int(ghTable, (char *)Cudd_Regular(x), &value)) {
+ value |= 1;
+ } else {
+ value = 1;
+ }
+ if (st_insert(ghTable, (char *)Cudd_Regular(x), (char *)(long)value) == ST_OUT_OF_MEM) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return NULL;
+ }
+ return(factors);
+ }
+
+ /* Seprate variable and child */
+ if (factorsNv->h == one) {
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ factors = ALLOC(Conjuncts, 1);
+ if (factors == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ Cudd_RecursiveDeref(dd, x);
+ return(NULL);
+ }
+ factors->g = factorsNv->g;
+ factors->h = x;
+ /* cache the result. */
+ if (st_insert(cacheTable, (char *)node, (char *)factors) == ST_OUT_OF_MEM) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ Cudd_RecursiveDeref(dd, x);
+ FREE(factors);
+ return(NULL);
+ }
+ /* store x in h table, the other node is already in the table */
+ if (st_lookup_int(ghTable, (char *)Cudd_Regular(x), &value)) {
+ value |= 2;
+ } else {
+ value = 2;
+ }
+ if (st_insert(ghTable, (char *)Cudd_Regular(x), (char *)(long)value) == ST_OUT_OF_MEM) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return NULL;
+ }
+ return(factors);
+ }
+
+ G = Cudd_Regular(factorsNv->g);
+ Gv = cuddT(G);
+ Gnv = cuddE(G);
+ Gv = Cudd_NotCond(Gv, Cudd_IsComplement(node));
+ Gnv = Cudd_NotCond(Gnv, Cudd_IsComplement(node));
+ /* if the child below is a variable */
+ if ((Gv == zero) || (Gnv == zero)) {
+ h = factorsNv->h;
+ g = cuddBddAndRecur(dd, x, factorsNv->g);
+ if (g != NULL) cuddRef(g);
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ Cudd_RecursiveDeref(dd, x);
+ if (g == NULL) {
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ return NULL;
+ }
+ /* CheckTablesCacheAndReturn responsible for allocating
+ * factors structure., g,h referenced for cache store the
+ */
+ factors = CheckTablesCacheAndReturn(node,
+ g,
+ h,
+ ghTable,
+ cacheTable);
+ if (factors == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd, g);
+ Cudd_RecursiveDeref(dd, h);
+ }
+ return(factors);
+ }
+
+ H = Cudd_Regular(factorsNv->h);
+ Hv = cuddT(H);
+ Hnv = cuddE(H);
+ Hv = Cudd_NotCond(Hv, Cudd_IsComplement(node));
+ Hnv = Cudd_NotCond(Hnv, Cudd_IsComplement(node));
+ /* if the child below is a variable */
+ if ((Hv == zero) || (Hnv == zero)) {
+ g = factorsNv->g;
+ h = cuddBddAndRecur(dd, x, factorsNv->h);
+ if (h!= NULL) cuddRef(h);
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ Cudd_RecursiveDeref(dd, x);
+ if (h == NULL) {
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ return NULL;
+ }
+ /* CheckTablesCacheAndReturn responsible for allocating
+ * factors structure.g,h referenced for table store
+ */
+ factors = CheckTablesCacheAndReturn(node,
+ g,
+ h,
+ ghTable,
+ cacheTable);
+ if (factors == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd, g);
+ Cudd_RecursiveDeref(dd, h);
+ }
+ return(factors);
+ }
+
+ /* build g1 = x*g; h1 = h */
+ /* build g2 = g; h2 = x*h */
+ Cudd_RecursiveDeref(dd, x);
+ h1 = factorsNv->h;
+ g1 = cuddBddAndRecur(dd, x, factorsNv->g);
+ if (g1 != NULL) cuddRef(g1);
+ if (g1 == NULL) {
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ return NULL;
+ }
+
+ g2 = factorsNv->g;
+ h2 = cuddBddAndRecur(dd, x, factorsNv->h);
+ if (h2 != NULL) cuddRef(h2);
+ if (h2 == NULL) {
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ return NULL;
+ }
+
+ /* check whether any pair is in tables */
+ factors = CheckInTables(node, g1, h1, g2, h2, ghTable, cacheTable, &outOfMem);
+ if (outOfMem) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd, g1);
+ Cudd_RecursiveDeref(dd, h1);
+ Cudd_RecursiveDeref(dd, g2);
+ Cudd_RecursiveDeref(dd, h2);
+ return NULL;
+ }
+ if (factors != NULL) {
+ if ((factors->g == g1) || (factors->g == h1)) {
+ Cudd_RecursiveDeref(dd, g2);
+ Cudd_RecursiveDeref(dd, h2);
+ } else {
+ Cudd_RecursiveDeref(dd, g1);
+ Cudd_RecursiveDeref(dd, h1);
+ }
+ return factors;
+ }
+
+ /* check for each pair in tables and choose one */
+ factors = PickOnePair(node,g1, h1, g2, h2, ghTable, cacheTable);
+ if (factors == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd, g1);
+ Cudd_RecursiveDeref(dd, h1);
+ Cudd_RecursiveDeref(dd, g2);
+ Cudd_RecursiveDeref(dd, h2);
+ } else {
+ /* now free what was created and not used */
+ if ((factors->g == g1) || (factors->g == h1)) {
+ Cudd_RecursiveDeref(dd, g2);
+ Cudd_RecursiveDeref(dd, h2);
+ } else {
+ Cudd_RecursiveDeref(dd, g1);
+ Cudd_RecursiveDeref(dd, h1);
+ }
+ }
+
+ return(factors);
+} /* end of ZeroCase */
+
+
+/**Function********************************************************************
+
+ Synopsis [Builds the conjuncts recursively, bottom up.]
+
+ Description [Builds the conjuncts recursively, bottom up. Constants
+ are returned as (f, f). The cache is checked for previously computed
+ result. The decomposition points are determined by the local
+ reference count of this node and the longest distance from the
+ constant. At the decomposition point, the factors returned are (f,
+ 1). Recur on the two children. The order is determined by the
+ heavier branch. Combine the factors of the two children and pick the
+ one that already occurs in the gh table. Occurence in g is indicated
+ by value 1, occurence in h by 2, occurence in both 3.]
+
+ SideEffects []
+
+ SeeAlso [cuddConjunctsAux]
+
+******************************************************************************/
+static Conjuncts *
+BuildConjuncts(
+ DdManager * dd,
+ DdNode * node,
+ st_table * distanceTable,
+ st_table * cacheTable,
+ int approxDistance,
+ int maxLocalRef,
+ st_table * ghTable,
+ st_table * mintermTable)
+{
+ int topid, distance;
+ Conjuncts *factorsNv, *factorsNnv, *factors;
+ Conjuncts *dummy;
+ DdNode *N, *Nv, *Nnv, *temp, *g1, *g2, *h1, *h2, *topv;
+ double minNv = 0.0, minNnv = 0.0;
+ double *doubleDummy;
+ int switched =0;
+ int outOfMem;
+ int freeNv = 0, freeNnv = 0, freeTemp;
+ NodeStat *nodeStat;
+ int value;
+
+ /* if f is constant, return (f,f) */
+ if (Cudd_IsConstant(node)) {
+ factors = ALLOC(Conjuncts, 1);
+ if (factors == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ factors->g = node;
+ factors->h = node;
+ return(FactorsComplement(factors));
+ }
+
+ /* If result (a pair of conjuncts) in cache, return the factors. */
+ if (st_lookup(cacheTable, (char *)node, (char **)&dummy)) {
+ factors = dummy;
+ return(factors);
+ }
+
+ /* check distance and local reference count of this node */
+ N = Cudd_Regular(node);
+ if (!st_lookup(distanceTable, (char *)N, (char **)&nodeStat)) {
+ (void) fprintf(dd->err, "Not in table, Something wrong\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+ distance = nodeStat->distance;
+
+ /* at or below decomposition point, return (f, 1) */
+ if (((nodeStat->localRef > maxLocalRef*2/3) &&
+ (distance < approxDistance*2/3)) ||
+ (distance <= approxDistance/4)) {
+ factors = ALLOC(Conjuncts, 1);
+ if (factors == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ /* alternate assigning (f,1) */
+ value = 0;
+ if (st_lookup_int(ghTable, (char *)Cudd_Regular(node), &value)) {
+ if (value == 3) {
+ if (!lastTimeG) {
+ factors->g = node;
+ factors->h = one;
+ lastTimeG = 1;
+ } else {
+ factors->g = one;
+ factors->h = node;
+ lastTimeG = 0;
+ }
+ } else if (value == 1) {
+ factors->g = node;
+ factors->h = one;
+ } else {
+ factors->g = one;
+ factors->h = node;
+ }
+ } else if (!lastTimeG) {
+ factors->g = node;
+ factors->h = one;
+ lastTimeG = 1;
+ value = 1;
+ if (st_insert(ghTable, (char *)Cudd_Regular(node), (char *)(long)value) == ST_OUT_OF_MEM) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ FREE(factors);
+ return NULL;
+ }
+ } else {
+ factors->g = one;
+ factors->h = node;
+ lastTimeG = 0;
+ value = 2;
+ if (st_insert(ghTable, (char *)Cudd_Regular(node), (char *)(long)value) == ST_OUT_OF_MEM) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ FREE(factors);
+ return NULL;
+ }
+ }
+ return(FactorsComplement(factors));
+ }
+
+ /* get the children and recur */
+ Nv = cuddT(N);
+ Nnv = cuddE(N);
+ Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
+ Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));
+
+ /* Choose which subproblem to solve first based on the number of
+ * minterms. We go first where there are more minterms.
+ */
+ if (!Cudd_IsConstant(Nv)) {
+ if (!st_lookup(mintermTable, (char *)Nv, (char **)&doubleDummy)) {
+ (void) fprintf(dd->err, "Not in table: Something wrong\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+ minNv = *doubleDummy;
+ }
+
+ if (!Cudd_IsConstant(Nnv)) {
+ if (!st_lookup(mintermTable, (char *)Nnv, (char **)&doubleDummy)) {
+ (void) fprintf(dd->err, "Not in table: Something wrong\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+ minNnv = *doubleDummy;
+ }
+
+ if (minNv < minNnv) {
+ temp = Nv;
+ Nv = Nnv;
+ Nnv = temp;
+ switched = 1;
+ }
+
+ /* build gt, ht recursively */
+ if (Nv != zero) {
+ factorsNv = BuildConjuncts(dd, Nv, distanceTable,
+ cacheTable, approxDistance, maxLocalRef,
+ ghTable, mintermTable);
+ if (factorsNv == NULL) return(NULL);
+ freeNv = FactorsNotStored(factorsNv);
+ factorsNv = (freeNv) ? FactorsUncomplement(factorsNv) : factorsNv;
+ cuddRef(factorsNv->g);
+ cuddRef(factorsNv->h);
+
+ /* Deal with the zero case */
+ if (Nnv == zero) {
+ /* is responsible for freeing factorsNv */
+ factors = ZeroCase(dd, node, factorsNv, ghTable,
+ cacheTable, switched);
+ if (freeNv) FREE(factorsNv);
+ return(factors);
+ }
+ }
+
+ /* build ge, he recursively */
+ if (Nnv != zero) {
+ factorsNnv = BuildConjuncts(dd, Nnv, distanceTable,
+ cacheTable, approxDistance, maxLocalRef,
+ ghTable, mintermTable);
+ if (factorsNnv == NULL) {
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ if (freeNv) FREE(factorsNv);
+ return(NULL);
+ }
+ freeNnv = FactorsNotStored(factorsNnv);
+ factorsNnv = (freeNnv) ? FactorsUncomplement(factorsNnv) : factorsNnv;
+ cuddRef(factorsNnv->g);
+ cuddRef(factorsNnv->h);
+
+ /* Deal with the zero case */
+ if (Nv == zero) {
+ /* is responsible for freeing factorsNv */
+ factors = ZeroCase(dd, node, factorsNnv, ghTable,
+ cacheTable, switched);
+ if (freeNnv) FREE(factorsNnv);
+ return(factors);
+ }
+ }
+
+ /* construct the 2 pairs */
+ /* g1 = x*gt + x'*ge; h1 = x*ht + x'*he; */
+ /* g2 = x*gt + x'*he; h2 = x*ht + x'*ge */
+ if (switched) {
+ factors = factorsNnv;
+ factorsNnv = factorsNv;
+ factorsNv = factors;
+ freeTemp = freeNv;
+ freeNv = freeNnv;
+ freeNnv = freeTemp;
+ }
+
+ /* Build the factors for this node. */
+ topid = N->index;
+ topv = dd->vars[topid];
+
+ g1 = cuddBddIteRecur(dd, topv, factorsNv->g, factorsNnv->g);
+ if (g1 == NULL) {
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ Cudd_RecursiveDeref(dd, factorsNnv->g);
+ Cudd_RecursiveDeref(dd, factorsNnv->h);
+ if (freeNv) FREE(factorsNv);
+ if (freeNnv) FREE(factorsNnv);
+ return(NULL);
+ }
+
+ cuddRef(g1);
+
+ h1 = cuddBddIteRecur(dd, topv, factorsNv->h, factorsNnv->h);
+ if (h1 == NULL) {
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ Cudd_RecursiveDeref(dd, factorsNnv->g);
+ Cudd_RecursiveDeref(dd, factorsNnv->h);
+ Cudd_RecursiveDeref(dd, g1);
+ if (freeNv) FREE(factorsNv);
+ if (freeNnv) FREE(factorsNnv);
+ return(NULL);
+ }
+
+ cuddRef(h1);
+
+ g2 = cuddBddIteRecur(dd, topv, factorsNv->g, factorsNnv->h);
+ if (g2 == NULL) {
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ Cudd_RecursiveDeref(dd, factorsNnv->g);
+ Cudd_RecursiveDeref(dd, factorsNnv->h);
+ Cudd_RecursiveDeref(dd, g1);
+ Cudd_RecursiveDeref(dd, h1);
+ if (freeNv) FREE(factorsNv);
+ if (freeNnv) FREE(factorsNnv);
+ return(NULL);
+ }
+ cuddRef(g2);
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ Cudd_RecursiveDeref(dd, factorsNnv->h);
+
+ h2 = cuddBddIteRecur(dd, topv, factorsNv->h, factorsNnv->g);
+ if (h2 == NULL) {
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ Cudd_RecursiveDeref(dd, factorsNnv->g);
+ Cudd_RecursiveDeref(dd, factorsNnv->h);
+ Cudd_RecursiveDeref(dd, g1);
+ Cudd_RecursiveDeref(dd, h1);
+ Cudd_RecursiveDeref(dd, g2);
+ if (freeNv) FREE(factorsNv);
+ if (freeNnv) FREE(factorsNnv);
+ return(NULL);
+ }
+ cuddRef(h2);
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ Cudd_RecursiveDeref(dd, factorsNnv->g);
+ if (freeNv) FREE(factorsNv);
+ if (freeNnv) FREE(factorsNnv);
+
+ /* check for each pair in tables and choose one */
+ factors = CheckInTables(node, g1, h1, g2, h2, ghTable, cacheTable, &outOfMem);
+ if (outOfMem) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd, g1);
+ Cudd_RecursiveDeref(dd, h1);
+ Cudd_RecursiveDeref(dd, g2);
+ Cudd_RecursiveDeref(dd, h2);
+ return(NULL);
+ }
+ if (factors != NULL) {
+ if ((factors->g == g1) || (factors->g == h1)) {
+ Cudd_RecursiveDeref(dd, g2);
+ Cudd_RecursiveDeref(dd, h2);
+ } else {
+ Cudd_RecursiveDeref(dd, g1);
+ Cudd_RecursiveDeref(dd, h1);
+ }
+ return(factors);
+ }
+
+ /* if not in tables, pick one pair */
+ factors = PickOnePair(node,g1, h1, g2, h2, ghTable, cacheTable);
+ if (factors == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd, g1);
+ Cudd_RecursiveDeref(dd, h1);
+ Cudd_RecursiveDeref(dd, g2);
+ Cudd_RecursiveDeref(dd, h2);
+ } else {
+ /* now free what was created and not used */
+ if ((factors->g == g1) || (factors->g == h1)) {
+ Cudd_RecursiveDeref(dd, g2);
+ Cudd_RecursiveDeref(dd, h2);
+ } else {
+ Cudd_RecursiveDeref(dd, g1);
+ Cudd_RecursiveDeref(dd, h1);
+ }
+ }
+
+ return(factors);
+
+} /* end of BuildConjuncts */
+
+
+/**Function********************************************************************
+
+ Synopsis [Procedure to compute two conjunctive factors of f and place in *c1 and *c2.]
+
+ Description [Procedure to compute two conjunctive factors of f and
+ place in *c1 and *c2. Sets up the required data - table of distances
+ from the constant and local reference count. Also minterm table. ]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddConjunctsAux(
+ DdManager * dd,
+ DdNode * f,
+ DdNode ** c1,
+ DdNode ** c2)
+{
+ st_table *distanceTable = NULL;
+ st_table *cacheTable = NULL;
+ st_table *mintermTable = NULL;
+ st_table *ghTable = NULL;
+ st_generator *stGen;
+ char *key, *value;
+ Conjuncts *factors;
+ int distance, approxDistance;
+ double max, minterms;
+ int freeFactors;
+ NodeStat *nodeStat;
+ int maxLocalRef;
+
+ /* initialize */
+ *c1 = NULL;
+ *c2 = NULL;
+
+ /* initialize distances table */
+ distanceTable = st_init_table(st_ptrcmp,st_ptrhash);
+ if (distanceTable == NULL) goto outOfMem;
+
+ /* make the entry for the constant */
+ nodeStat = ALLOC(NodeStat, 1);
+ if (nodeStat == NULL) goto outOfMem;
+ nodeStat->distance = 0;
+ nodeStat->localRef = 1;
+ if (st_insert(distanceTable, (char *)one, (char *)nodeStat) == ST_OUT_OF_MEM) {
+ goto outOfMem;
+ }
+
+ /* Count node distances from constant. */
+ nodeStat = CreateBotDist(f, distanceTable);
+ if (nodeStat == NULL) goto outOfMem;
+
+ /* set the distance for the decomposition points */
+ approxDistance = (DEPTH < nodeStat->distance) ? nodeStat->distance : DEPTH;
+ distance = nodeStat->distance;
+
+ if (distance < approxDistance) {
+ /* Too small to bother. */
+ *c1 = f;
+ *c2 = DD_ONE(dd);
+ cuddRef(*c1); cuddRef(*c2);
+ stGen = st_init_gen(distanceTable);
+ if (stGen == NULL) goto outOfMem;
+ while(st_gen(stGen, (char **)&key, (char **)&value)) {
+ FREE(value);
+ }
+ st_free_gen(stGen); stGen = NULL;
+ st_free_table(distanceTable);
+ return(1);
+ }
+
+ /* record the maximum local reference count */
+ maxLocalRef = 0;
+ stGen = st_init_gen(distanceTable);
+ if (stGen == NULL) goto outOfMem;
+ while(st_gen(stGen, (char **)&key, (char **)&value)) {
+ nodeStat = (NodeStat *)value;
+ maxLocalRef = (nodeStat->localRef > maxLocalRef) ?
+ nodeStat->localRef : maxLocalRef;
+ }
+ st_free_gen(stGen); stGen = NULL;
+
+
+ /* Count minterms for each node. */
+ max = pow(2.0, (double)Cudd_SupportSize(dd,f)); /* potential overflow */
+ mintermTable = st_init_table(st_ptrcmp,st_ptrhash);
+ if (mintermTable == NULL) goto outOfMem;
+ minterms = CountMinterms(f, max, mintermTable, dd->err);
+ if (minterms == -1.0) goto outOfMem;
+
+ lastTimeG = Cudd_Random() & 1;
+ cacheTable = st_init_table(st_ptrcmp, st_ptrhash);
+ if (cacheTable == NULL) goto outOfMem;
+ ghTable = st_init_table(st_ptrcmp, st_ptrhash);
+ if (ghTable == NULL) goto outOfMem;
+
+ /* Build conjuncts. */
+ factors = BuildConjuncts(dd, f, distanceTable, cacheTable,
+ approxDistance, maxLocalRef, ghTable, mintermTable);
+ if (factors == NULL) goto outOfMem;
+
+ /* free up tables */
+ stGen = st_init_gen(distanceTable);
+ if (stGen == NULL) goto outOfMem;
+ while(st_gen(stGen, (char **)&key, (char **)&value)) {
+ FREE(value);
+ }
+ st_free_gen(stGen); stGen = NULL;
+ st_free_table(distanceTable); distanceTable = NULL;
+ st_free_table(ghTable); ghTable = NULL;
+
+ stGen = st_init_gen(mintermTable);
+ if (stGen == NULL) goto outOfMem;
+ while(st_gen(stGen, (char **)&key, (char **)&value)) {
+ FREE(value);
+ }
+ st_free_gen(stGen); stGen = NULL;
+ st_free_table(mintermTable); mintermTable = NULL;
+
+ freeFactors = FactorsNotStored(factors);
+ factors = (freeFactors) ? FactorsUncomplement(factors) : factors;
+ if (factors != NULL) {
+ *c1 = factors->g;
+ *c2 = factors->h;
+ cuddRef(*c1);
+ cuddRef(*c2);
+ if (freeFactors) FREE(factors);
+
+#if 0
+ if ((*c1 == f) && (!Cudd_IsConstant(f))) {
+ assert(*c2 == one);
+ }
+ if ((*c2 == f) && (!Cudd_IsConstant(f))) {
+ assert(*c1 == one);
+ }
+
+ if ((*c1 != one) && (!Cudd_IsConstant(f))) {
+ assert(!Cudd_bddLeq(dd, *c2, *c1));
+ }
+ if ((*c2 != one) && (!Cudd_IsConstant(f))) {
+ assert(!Cudd_bddLeq(dd, *c1, *c2));
+ }
+#endif
+ }
+
+ stGen = st_init_gen(cacheTable);
+ if (stGen == NULL) goto outOfMem;
+ while(st_gen(stGen, (char **)&key, (char **)&value)) {
+ ConjunctsFree(dd, (Conjuncts *)value);
+ }
+ st_free_gen(stGen); stGen = NULL;
+
+ st_free_table(cacheTable); cacheTable = NULL;
+
+ return(1);
+
+outOfMem:
+ if (distanceTable != NULL) {
+ stGen = st_init_gen(distanceTable);
+ if (stGen == NULL) goto outOfMem;
+ while(st_gen(stGen, (char **)&key, (char **)&value)) {
+ FREE(value);
+ }
+ st_free_gen(stGen); stGen = NULL;
+ st_free_table(distanceTable); distanceTable = NULL;
+ }
+ if (mintermTable != NULL) {
+ stGen = st_init_gen(mintermTable);
+ if (stGen == NULL) goto outOfMem;
+ while(st_gen(stGen, (char **)&key, (char **)&value)) {
+ FREE(value);
+ }
+ st_free_gen(stGen); stGen = NULL;
+ st_free_table(mintermTable); mintermTable = NULL;
+ }
+ if (ghTable != NULL) st_free_table(ghTable);
+ if (cacheTable != NULL) {
+ stGen = st_init_gen(cacheTable);
+ if (stGen == NULL) goto outOfMem;
+ while(st_gen(stGen, (char **)&key, (char **)&value)) {
+ ConjunctsFree(dd, (Conjuncts *)value);
+ }
+ st_free_gen(stGen); stGen = NULL;
+ st_free_table(cacheTable); cacheTable = NULL;
+ }
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+
+} /* end of cuddConjunctsAux */
diff --git a/src/bdd/cudd/cuddEssent.c b/src/bdd/cudd/cuddEssent.c
new file mode 100644
index 00000000..7bd48c5a
--- /dev/null
+++ b/src/bdd/cudd/cuddEssent.c
@@ -0,0 +1,279 @@
+/**CFile***********************************************************************
+
+ FileName [cuddEssent.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions for the detection of essential variables.]
+
+ Description [External procedures included in this file:
+ <ul>
+ <li> Cudd_FindEssential()
+ <li> Cudd_bddIsVarEssential()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> ddFindEssentialRecur()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddEssent.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static DdNode * ddFindEssentialRecur ARGS((DdManager *dd, DdNode *f));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the essential variables of a DD.]
+
+ Description [Returns the cube of the essential variables. A positive
+ literal means that the variable must be set to 1 for the function to be
+ 1. A negative literal means that the variable must be set to 0 for the
+ function to be 1. Returns a pointer to the cube BDD if successful;
+ NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddIsVarEssential]
+
+******************************************************************************/
+DdNode *
+Cudd_FindEssential(
+ DdManager * dd,
+ DdNode * f)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = ddFindEssentialRecur(dd,f);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_FindEssential */
+
+
+/**Function********************************************************************
+
+ Synopsis [Determines whether a given variable is essential with a
+ given phase in a BDD.]
+
+ Description [Determines whether a given variable is essential with a
+ given phase in a BDD. Uses Cudd_bddIteConstant. Returns 1 if phase == 1
+ and f-->x_id, or if phase == 0 and f-->x_id'.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_FindEssential]
+
+******************************************************************************/
+int
+Cudd_bddIsVarEssential(
+ DdManager * manager,
+ DdNode * f,
+ int id,
+ int phase)
+{
+ DdNode *var;
+ int res;
+ DdNode *one, *zero;
+
+ one = DD_ONE(manager);
+ zero = Cudd_Not(one);
+
+ var = cuddUniqueInter(manager, id, one, zero);
+
+ var = Cudd_NotCond(var,phase == 0);
+
+ res = Cudd_bddIteConstant(manager, Cudd_Not(f), one, var) == one;
+
+ return(res);
+
+} /* end of Cudd_bddIsVarEssential */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_FindEssential.]
+
+ Description [Implements the recursive step of Cudd_FindEssential.
+ Returns a pointer to the cube BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static DdNode *
+ddFindEssentialRecur(
+ DdManager * dd,
+ DdNode * f)
+{
+ DdNode *T, *E, *F;
+ DdNode *essT, *essE, *res;
+ int index;
+ DdNode *one, *lzero, *azero;
+
+ one = DD_ONE(dd);
+ F = Cudd_Regular(f);
+ /* If f is constant the set of essential variables is empty. */
+ if (cuddIsConstant(F)) return(one);
+
+ res = cuddCacheLookup1(dd,Cudd_FindEssential,f);
+ if (res != NULL) {
+ return(res);
+ }
+
+ lzero = Cudd_Not(one);
+ azero = DD_ZERO(dd);
+ /* Find cofactors: here f is non-constant. */
+ T = cuddT(F);
+ E = cuddE(F);
+ if (Cudd_IsComplement(f)) {
+ T = Cudd_Not(T); E = Cudd_Not(E);
+ }
+
+ index = F->index;
+ if (Cudd_IsConstant(T) && T != lzero && T != azero) {
+ /* if E is zero, index is essential, otherwise there are no
+ ** essentials, because index is not essential and no other variable
+ ** can be, since setting index = 1 makes the function constant and
+ ** different from 0.
+ */
+ if (E == lzero || E == azero) {
+ res = dd->vars[index];
+ } else {
+ res = one;
+ }
+ } else if (T == lzero || T == azero) {
+ if (Cudd_IsConstant(E)) { /* E cannot be zero here */
+ res = Cudd_Not(dd->vars[index]);
+ } else { /* E == non-constant */
+ /* find essentials in the else branch */
+ essE = ddFindEssentialRecur(dd,E);
+ if (essE == NULL) {
+ return(NULL);
+ }
+ cuddRef(essE);
+
+ /* add index to the set with negative phase */
+ res = cuddUniqueInter(dd,index,one,Cudd_Not(essE));
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd,essE);
+ return(NULL);
+ }
+ res = Cudd_Not(res);
+ cuddDeref(essE);
+ }
+ } else { /* T == non-const */
+ if (E == lzero || E == azero) {
+ /* find essentials in the then branch */
+ essT = ddFindEssentialRecur(dd,T);
+ if (essT == NULL) {
+ return(NULL);
+ }
+ cuddRef(essT);
+
+ /* add index to the set with positive phase */
+ /* use And because essT may be complemented */
+ res = cuddBddAndRecur(dd,dd->vars[index],essT);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd,essT);
+ return(NULL);
+ }
+ cuddDeref(essT);
+ } else if (!Cudd_IsConstant(E)) {
+ /* if E is a non-zero constant there are no essentials
+ ** because T is non-constant.
+ */
+ essT = ddFindEssentialRecur(dd,T);
+ if (essT == NULL) {
+ return(NULL);
+ }
+ if (essT == one) {
+ res = one;
+ } else {
+ cuddRef(essT);
+ essE = ddFindEssentialRecur(dd,E);
+ if (essE == NULL) {
+ Cudd_RecursiveDeref(dd,essT);
+ return(NULL);
+ }
+ cuddRef(essE);
+
+ /* res = intersection(essT, essE) */
+ res = cuddBddLiteralSetIntersectionRecur(dd,essT,essE);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd,essT);
+ Cudd_RecursiveDeref(dd,essE);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd,essT);
+ Cudd_RecursiveDeref(dd,essE);
+ cuddDeref(res);
+ }
+ } else { /* E is a non-zero constant */
+ res = one;
+ }
+ }
+
+ cuddCacheInsert1(dd,Cudd_FindEssential, f, res);
+ return(res);
+
+} /* end of ddFindEssentialRecur */
+
diff --git a/src/bdd/cudd/cuddExact.c b/src/bdd/cudd/cuddExact.c
new file mode 100644
index 00000000..6a81406b
--- /dev/null
+++ b/src/bdd/cudd/cuddExact.c
@@ -0,0 +1,1004 @@
+/**CFile***********************************************************************
+
+ FileName [cuddExact.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions for exact variable reordering.]
+
+ Description [External procedures included in this file:
+ <ul>
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddExact()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> getMaxBinomial()
+ <li> gcd()
+ <li> getMatrix()
+ <li> freeMatrix()
+ <li> getLevelKeys()
+ <li> ddShuffle()
+ <li> ddSiftUp()
+ <li> updateUB()
+ <li> ddCountRoots()
+ <li> ddClearGlobal()
+ <li> computeLB()
+ <li> updateEntry()
+ <li> pushDown()
+ <li> initSymmInfo()
+ </ul>]
+
+ Author [Cheng Hua, Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddExact.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+#ifdef DD_STATS
+static int ddTotalShuffles;
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int getMaxBinomial ARGS((int n));
+static int gcd ARGS((int x, int y));
+static DdHalfWord ** getMatrix ARGS((int rows, int cols));
+static void freeMatrix ARGS((DdHalfWord **matrix));
+static int getLevelKeys ARGS((DdManager *table, int l));
+static int ddShuffle ARGS((DdManager *table, DdHalfWord *permutation, int lower, int upper));
+static int ddSiftUp ARGS((DdManager *table, int x, int xLow));
+static int updateUB ARGS((DdManager *table, int oldBound, DdHalfWord *bestOrder, int lower, int upper));
+static int ddCountRoots ARGS((DdManager *table, int lower, int upper));
+static void ddClearGlobal ARGS((DdManager *table, int lower, int maxlevel));
+static int computeLB ARGS((DdManager *table, DdHalfWord *order, int roots, int cost, int lower, int upper, int level));
+static int updateEntry ARGS((DdManager *table, DdHalfWord *order, int level, int cost, DdHalfWord **orders, int *costs, int subsets, char *mask, int lower, int upper));
+static void pushDown ARGS((DdHalfWord *order, int j, int level));
+static DdHalfWord * initSymmInfo ARGS((DdManager *table, int lower, int upper));
+static int checkSymmInfo ARGS((DdManager *table, DdHalfWord *symmInfo, int index, int level));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Exact variable ordering algorithm.]
+
+ Description [Exact variable ordering algorithm. Finds an optimum
+ order for the variables between lower and upper. Returns 1 if
+ successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddExact(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int k, i, j;
+ int maxBinomial, oldSubsets, newSubsets;
+ int subsetCost;
+ int size; /* number of variables to be reordered */
+ int unused, nvars, level, result;
+ int upperBound, lowerBound, cost;
+ int roots;
+ char *mask = NULL;
+ DdHalfWord *symmInfo = NULL;
+ DdHalfWord **newOrder = NULL;
+ DdHalfWord **oldOrder = NULL;
+ int *newCost = NULL;
+ int *oldCost = NULL;
+ DdHalfWord **tmpOrder;
+ int *tmpCost;
+ DdHalfWord *bestOrder = NULL;
+ DdHalfWord *order;
+#ifdef DD_STATS
+ int ddTotalSubsets;
+#endif
+
+ /* Restrict the range to be reordered by excluding unused variables
+ ** at the two ends. */
+ while (table->subtables[lower].keys == 1 &&
+ table->vars[table->invperm[lower]]->ref == 1 &&
+ lower < upper)
+ lower++;
+ while (table->subtables[upper].keys == 1 &&
+ table->vars[table->invperm[upper]]->ref == 1 &&
+ lower < upper)
+ upper--;
+ if (lower == upper) return(1); /* trivial problem */
+
+ /* Apply symmetric sifting to get a good upper bound and to extract
+ ** symmetry information. */
+ result = cuddSymmSiftingConv(table,lower,upper);
+ if (result == 0) goto cuddExactOutOfMem;
+
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\n");
+ ddTotalShuffles = 0;
+ ddTotalSubsets = 0;
+#endif
+
+ /* Initialization. */
+ nvars = table->size;
+ size = upper - lower + 1;
+ /* Count unused variable among those to be reordered. This is only
+ ** used to compute maxBinomial. */
+ unused = 0;
+ for (i = lower + 1; i < upper; i++) {
+ if (table->subtables[i].keys == 1 &&
+ table->vars[table->invperm[i]]->ref == 1)
+ unused++;
+ }
+
+ /* Find the maximum number of subsets we may have to store. */
+ maxBinomial = getMaxBinomial(size - unused);
+ if (maxBinomial == -1) goto cuddExactOutOfMem;
+
+ newOrder = getMatrix(maxBinomial, size);
+ if (newOrder == NULL) goto cuddExactOutOfMem;
+
+ newCost = ALLOC(int, maxBinomial);
+ if (newCost == NULL) goto cuddExactOutOfMem;
+
+ oldOrder = getMatrix(maxBinomial, size);
+ if (oldOrder == NULL) goto cuddExactOutOfMem;
+
+ oldCost = ALLOC(int, maxBinomial);
+ if (oldCost == NULL) goto cuddExactOutOfMem;
+
+ bestOrder = ALLOC(DdHalfWord, size);
+ if (bestOrder == NULL) goto cuddExactOutOfMem;
+
+ mask = ALLOC(char, nvars);
+ if (mask == NULL) goto cuddExactOutOfMem;
+
+ symmInfo = initSymmInfo(table, lower, upper);
+ if (symmInfo == NULL) goto cuddExactOutOfMem;
+
+ roots = ddCountRoots(table, lower, upper);
+
+ /* Initialize the old order matrix for the empty subset and the best
+ ** order to the current order. The cost for the empty subset includes
+ ** the cost of the levels between upper and the constants. These levels
+ ** are not going to change. Hence, we count them only once.
+ */
+ oldSubsets = 1;
+ for (i = 0; i < size; i++) {
+ oldOrder[0][i] = bestOrder[i] = (DdHalfWord) table->invperm[i+lower];
+ }
+ subsetCost = table->constants.keys;
+ for (i = upper + 1; i < nvars; i++)
+ subsetCost += getLevelKeys(table,i);
+ oldCost[0] = subsetCost;
+ /* The upper bound is initialized to the current size of the BDDs. */
+ upperBound = table->keys - table->isolated;
+
+ /* Now consider subsets of increasing size. */
+ for (k = 1; k <= size; k++) {
+#if DD_STATS
+ (void) fprintf(table->out,"Processing subsets of size %d\n", k);
+ fflush(table->out);
+#endif
+ newSubsets = 0;
+ level = size - k; /* offset of first bottom variable */
+
+ for (i = 0; i < oldSubsets; i++) { /* for each subset of size k-1 */
+ order = oldOrder[i];
+ cost = oldCost[i];
+ lowerBound = computeLB(table, order, roots, cost, lower, upper,
+ level);
+ if (lowerBound >= upperBound)
+ continue;
+ /* Impose new order. */
+ result = ddShuffle(table, order, lower, upper);
+ if (result == 0) goto cuddExactOutOfMem;
+ upperBound = updateUB(table,upperBound,bestOrder,lower,upper);
+ /* For each top bottom variable. */
+ for (j = level; j >= 0; j--) {
+ /* Skip unused variables. */
+ if (table->subtables[j+lower-1].keys == 1 &&
+ table->vars[table->invperm[j+lower-1]]->ref == 1) continue;
+ /* Find cost under this order. */
+ subsetCost = cost + getLevelKeys(table, lower + level);
+ newSubsets = updateEntry(table, order, level, subsetCost,
+ newOrder, newCost, newSubsets, mask,
+ lower, upper);
+ if (j == 0)
+ break;
+ if (checkSymmInfo(table, symmInfo, order[j-1], level) == 0)
+ continue;
+ pushDown(order,j-1,level);
+ /* Impose new order. */
+ result = ddShuffle(table, order, lower, upper);
+ if (result == 0) goto cuddExactOutOfMem;
+ upperBound = updateUB(table,upperBound,bestOrder,lower,upper);
+ } /* for each bottom variable */
+ } /* for each subset of size k */
+
+ /* New orders become old orders in preparation for next iteration. */
+ tmpOrder = oldOrder; tmpCost = oldCost;
+ oldOrder = newOrder; oldCost = newCost;
+ newOrder = tmpOrder; newCost = tmpCost;
+#ifdef DD_STATS
+ ddTotalSubsets += newSubsets;
+#endif
+ oldSubsets = newSubsets;
+ }
+ result = ddShuffle(table, bestOrder, lower, upper);
+ if (result == 0) goto cuddExactOutOfMem;
+#ifdef DD_STATS
+#ifdef DD_VERBOSE
+ (void) fprintf(table->out,"\n");
+#endif
+ (void) fprintf(table->out,"#:S_EXACT %8d: total subsets\n",
+ ddTotalSubsets);
+ (void) fprintf(table->out,"#:H_EXACT %8d: total shuffles",
+ ddTotalShuffles);
+#endif
+
+ freeMatrix(newOrder);
+ freeMatrix(oldOrder);
+ FREE(bestOrder);
+ FREE(oldCost);
+ FREE(newCost);
+ FREE(symmInfo);
+ FREE(mask);
+ return(1);
+
+cuddExactOutOfMem:
+
+ if (newOrder != NULL) freeMatrix(newOrder);
+ if (oldOrder != NULL) freeMatrix(oldOrder);
+ if (bestOrder != NULL) FREE(bestOrder);
+ if (oldCost != NULL) FREE(oldCost);
+ if (newCost != NULL) FREE(newCost);
+ if (symmInfo != NULL) FREE(symmInfo);
+ if (mask != NULL) FREE(mask);
+ table->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+
+} /* end of cuddExact */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the maximum value of (n choose k) for a given n.]
+
+ Description [Computes the maximum value of (n choose k) for a given
+ n. The maximum value occurs for k = n/2 when n is even, or k =
+ (n-1)/2 when n is odd. The algorithm used in this procedure is
+ quite inefficient, but it avoids intermediate overflow problems.
+ Returns the computed value if successful; -1 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+getMaxBinomial(
+ int n)
+{
+ int *numerator;
+ int i, j, k, y, g, result;
+
+ k = (n & ~1) >> 1;
+
+ numerator = ALLOC(int,k);
+ if (numerator == NULL) return(-1);
+
+ for (i = 0; i < k; i++)
+ numerator[i] = n - i;
+
+ for (i = k; i > 1; i--) {
+ y = i;
+ for (j = 0; j < k; j++) {
+ if (numerator[j] == 1) continue;
+ g = gcd(numerator[j], y);
+ if (g != 1) {
+ numerator[j] /= g;
+ if (y == g) break;
+ y /= g;
+ }
+ }
+ }
+
+ result = 1;
+ for (i = 0; i < k; i++)
+ result *= numerator[i];
+
+ FREE(numerator);
+ return(result);
+
+} /* end of getMaxBinomial */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the gcd of two integers.]
+
+ Description [Returns the gcd of two integers. Uses the binary GCD
+ algorithm described in Cormen, Leiserson, and Rivest.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+gcd(
+ int x,
+ int y)
+{
+ int a;
+ int b;
+ int lsbMask;
+
+ /* GCD(n,0) = n. */
+ if (x == 0) return(y);
+ if (y == 0) return(x);
+
+ a = x; b = y; lsbMask = 1;
+
+ /* Here both a and b are != 0. The iteration maintains this invariant.
+ ** Hence, we only need to check for when they become equal.
+ */
+ while (a != b) {
+ if (a & lsbMask) {
+ if (b & lsbMask) { /* both odd */
+ if (a < b) {
+ b = (b - a) >> 1;
+ } else {
+ a = (a - b) >> 1;
+ }
+ } else { /* a odd, b even */
+ b >>= 1;
+ }
+ } else {
+ if (b & lsbMask) { /* a even, b odd */
+ a >>= 1;
+ } else { /* both even */
+ lsbMask <<= 1;
+ }
+ }
+ }
+
+ return(a);
+
+} /* end of gcd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Allocates a two-dimensional matrix of ints.]
+
+ Description [Allocates a two-dimensional matrix of ints.
+ Returns the pointer to the matrix if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [freeMatrix]
+
+******************************************************************************/
+static DdHalfWord **
+getMatrix(
+ int rows /* number of rows */,
+ int cols /* number of columns */)
+{
+ DdHalfWord **matrix;
+ int i;
+
+ if (cols*rows == 0) return(NULL);
+ matrix = ALLOC(DdHalfWord *, rows);
+ if (matrix == NULL) return(NULL);
+ matrix[0] = ALLOC(DdHalfWord, cols*rows);
+ if (matrix[0] == NULL) return(NULL);
+ for (i = 1; i < rows; i++) {
+ matrix[i] = matrix[i-1] + cols;
+ }
+ return(matrix);
+
+} /* end of getMatrix */
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees a two-dimensional matrix allocated by getMatrix.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [getMatrix]
+
+******************************************************************************/
+static void
+freeMatrix(
+ DdHalfWord ** matrix)
+{
+ FREE(matrix[0]);
+ FREE(matrix);
+ return;
+
+} /* end of freeMatrix */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the number of nodes at one level of a unique table.]
+
+ Description [Returns the number of nodes at one level of a unique table.
+ The projection function, if isolated, is not counted.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+getLevelKeys(
+ DdManager * table,
+ int l)
+{
+ int isolated;
+ int x; /* x is an index */
+
+ x = table->invperm[l];
+ isolated = table->vars[x]->ref == 1;
+
+ return(table->subtables[l].keys - isolated);
+
+} /* end of getLevelKeys */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders variables according to a given permutation.]
+
+ Description [Reorders variables according to a given permutation.
+ The i-th permutation array contains the index of the variable that
+ should be brought to the i-th level. ddShuffle assumes that no
+ dead nodes are present and that the interaction matrix is properly
+ initialized. The reordering is achieved by a series of upward sifts.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+ddShuffle(
+ DdManager * table,
+ DdHalfWord * permutation,
+ int lower,
+ int upper)
+{
+ DdHalfWord index;
+ int level;
+ int position;
+ int numvars;
+ int result;
+#ifdef DD_STATS
+ long localTime;
+ int initialSize;
+#ifdef DD_VERBOSE
+ int finalSize;
+#endif
+ int previousSize;
+#endif
+
+#ifdef DD_STATS
+ localTime = util_cpu_time();
+ initialSize = table->keys - table->isolated;
+#endif
+
+ numvars = table->size;
+
+#if 0
+ (void) fprintf(table->out,"%d:", ddTotalShuffles);
+ for (level = 0; level < numvars; level++) {
+ (void) fprintf(table->out," %d", table->invperm[level]);
+ }
+ (void) fprintf(table->out,"\n");
+#endif
+
+ for (level = 0; level <= upper - lower; level++) {
+ index = permutation[level];
+ position = table->perm[index];
+#ifdef DD_STATS
+ previousSize = table->keys - table->isolated;
+#endif
+ result = ddSiftUp(table,position,level+lower);
+ if (!result) return(0);
+ }
+
+#ifdef DD_STATS
+ ddTotalShuffles++;
+#ifdef DD_VERBOSE
+ finalSize = table->keys - table->isolated;
+ if (finalSize < initialSize) {
+ (void) fprintf(table->out,"-");
+ } else if (finalSize > initialSize) {
+ (void) fprintf(table->out,"+");
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ if ((ddTotalShuffles & 63) == 0) (void) fprintf(table->out,"\n");
+ fflush(table->out);
+#endif
+#endif
+
+ return(1);
+
+} /* end of ddShuffle */
+
+
+/**Function********************************************************************
+
+ Synopsis [Moves one variable up.]
+
+ Description [Takes a variable from position x and sifts it up to
+ position xLow; xLow should be less than or equal to x.
+ Returns 1 if successful; 0 otherwise]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+ddSiftUp(
+ DdManager * table,
+ int x,
+ int xLow)
+{
+ int y;
+ int size;
+
+ y = cuddNextLow(table,x);
+ while (y >= xLow) {
+ size = cuddSwapInPlace(table,y,x);
+ if (size == 0) {
+ return(0);
+ }
+ x = y;
+ y = cuddNextLow(table,x);
+ }
+ return(1);
+
+} /* end of ddSiftUp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Updates the upper bound and saves the best order seen so far.]
+
+ Description [Updates the upper bound and saves the best order seen so far.
+ Returns the current value of the upper bound.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+updateUB(
+ DdManager * table,
+ int oldBound,
+ DdHalfWord * bestOrder,
+ int lower,
+ int upper)
+{
+ int i;
+ int newBound = table->keys - table->isolated;
+
+ if (newBound < oldBound) {
+#ifdef DD_STATS
+ (void) fprintf(table->out,"New upper bound = %d\n", newBound);
+ fflush(table->out);
+#endif
+ for (i = lower; i <= upper; i++)
+ bestOrder[i-lower] = (DdHalfWord) table->invperm[i];
+ return(newBound);
+ } else {
+ return(oldBound);
+ }
+
+} /* end of updateUB */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the number of roots.]
+
+ Description [Counts the number of roots at the levels between lower and
+ upper. The computation is based on breadth-first search.
+ A node is a root if it is not reachable from any previously visited node.
+ (All the nodes at level lower are therefore considered roots.)
+ The visited flag uses the LSB of the next pointer. Returns the root
+ count. The roots that are constant nodes are always ignored.]
+
+ SideEffects [None]
+
+ SeeAlso [ddClearGlobal]
+
+******************************************************************************/
+static int
+ddCountRoots(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int i,j;
+ DdNode *f;
+ DdNodePtr *nodelist;
+ DdNode *sentinel = &(table->sentinel);
+ int slots;
+ int roots = 0;
+ int maxlevel = lower;
+
+ for (i = lower; i <= upper; i++) {
+ nodelist = table->subtables[i].nodelist;
+ slots = table->subtables[i].slots;
+ for (j = 0; j < slots; j++) {
+ f = nodelist[j];
+ while (f != sentinel) {
+ /* A node is a root of the DAG if it cannot be
+ ** reached by nodes above it. If a node was never
+ ** reached during the previous depth-first searches,
+ ** then it is a root, and we start a new depth-first
+ ** search from it.
+ */
+ if (!Cudd_IsComplement(f->next)) {
+ if (f != table->vars[f->index]) {
+ roots++;
+ }
+ }
+ if (!Cudd_IsConstant(cuddT(f))) {
+ cuddT(f)->next = Cudd_Complement(cuddT(f)->next);
+ if (table->perm[cuddT(f)->index] > maxlevel)
+ maxlevel = table->perm[cuddT(f)->index];
+ }
+ if (!Cudd_IsConstant(cuddE(f))) {
+ Cudd_Regular(cuddE(f))->next =
+ Cudd_Complement(Cudd_Regular(cuddE(f))->next);
+ if (table->perm[Cudd_Regular(cuddE(f))->index] > maxlevel)
+ maxlevel = table->perm[Cudd_Regular(cuddE(f))->index];
+ }
+ f = Cudd_Regular(f->next);
+ }
+ }
+ }
+ ddClearGlobal(table, lower, maxlevel);
+
+ return(roots);
+
+} /* end of ddCountRoots */
+
+
+/**Function********************************************************************
+
+ Synopsis [Scans the DD and clears the LSB of the next pointers.]
+
+ Description [Scans the DD and clears the LSB of the next pointers.
+ The LSB of the next pointers are used as markers to tell whether a
+ node was reached. Once the roots are counted, these flags are
+ reset.]
+
+ SideEffects [None]
+
+ SeeAlso [ddCountRoots]
+
+******************************************************************************/
+static void
+ddClearGlobal(
+ DdManager * table,
+ int lower,
+ int maxlevel)
+{
+ int i,j;
+ DdNode *f;
+ DdNodePtr *nodelist;
+ DdNode *sentinel = &(table->sentinel);
+ int slots;
+
+ for (i = lower; i <= maxlevel; i++) {
+ nodelist = table->subtables[i].nodelist;
+ slots = table->subtables[i].slots;
+ for (j = 0; j < slots; j++) {
+ f = nodelist[j];
+ while (f != sentinel) {
+ f->next = Cudd_Regular(f->next);
+ f = f->next;
+ }
+ }
+ }
+
+} /* end of ddClearGlobal */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes a lower bound on the size of a BDD.]
+
+ Description [Computes a lower bound on the size of a BDD from the
+ following factors:
+ <ul>
+ <li> size of the lower part of it;
+ <li> size of the part of the upper part not subjected to reordering;
+ <li> number of roots in the part of the BDD subjected to reordering;
+ <li> variable in the support of the roots in the upper part of the
+ BDD subjected to reordering.
+ <ul/>]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+computeLB(
+ DdManager * table /* manager */,
+ DdHalfWord * order /* optimal order for the subset */,
+ int roots /* roots between lower and upper */,
+ int cost /* minimum cost for the subset */,
+ int lower /* lower level to be reordered */,
+ int upper /* upper level to be reordered */,
+ int level /* offset for the current top bottom var */
+ )
+{
+ int i;
+ int lb = cost;
+ int lb1 = 0;
+ int lb2;
+ int support;
+ DdHalfWord ref;
+
+ /* The levels not involved in reordering are not going to change.
+ ** Add their sizes to the lower bound.
+ */
+ for (i = 0; i < lower; i++) {
+ lb += getLevelKeys(table,i);
+ }
+ /* If a variable is in the support, then there is going
+ ** to be at least one node labeled by that variable.
+ */
+ for (i = lower; i <= lower+level; i++) {
+ support = table->subtables[i].keys > 1 ||
+ table->vars[order[i-lower]]->ref > 1;
+ lb1 += support;
+ }
+
+ /* Estimate the number of nodes required to connect the roots to
+ ** the nodes in the bottom part. */
+ if (lower+level+1 < table->size) {
+ if (lower+level < upper)
+ ref = table->vars[order[level+1]]->ref;
+ else
+ ref = table->vars[table->invperm[upper+1]]->ref;
+ lb2 = table->subtables[lower+level+1].keys -
+ (ref > (DdHalfWord) 1) - roots;
+ } else {
+ lb2 = 0;
+ }
+
+ lb += lb1 > lb2 ? lb1 : lb2;
+
+ return(lb);
+
+} /* end of computeLB */
+
+
+/**Function********************************************************************
+
+ Synopsis [Updates entry for a subset.]
+
+ Description [Updates entry for a subset. Finds the subset, if it exists.
+ If the new order for the subset has lower cost, or if the subset did not
+ exist, it stores the new order and cost. Returns the number of subsets
+ currently in the table.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+updateEntry(
+ DdManager * table,
+ DdHalfWord * order,
+ int level,
+ int cost,
+ DdHalfWord ** orders,
+ int * costs,
+ int subsets,
+ char * mask,
+ int lower,
+ int upper)
+{
+ int i, j;
+ int size = upper - lower + 1;
+
+ /* Build a mask that says what variables are in this subset. */
+ for (i = lower; i <= upper; i++)
+ mask[table->invperm[i]] = 0;
+ for (i = level; i < size; i++)
+ mask[order[i]] = 1;
+
+ /* Check each subset until a match is found or all subsets are examined. */
+ for (i = 0; i < subsets; i++) {
+ DdHalfWord *subset = orders[i];
+ for (j = level; j < size; j++) {
+ if (mask[subset[j]] == 0)
+ break;
+ }
+ if (j == size) /* no mismatches: success */
+ break;
+ }
+ if (i == subsets || cost < costs[i]) { /* add or replace */
+ for (j = 0; j < size; j++)
+ orders[i][j] = order[j];
+ costs[i] = cost;
+ subsets += (i == subsets);
+ }
+ return(subsets);
+
+} /* end of updateEntry */
+
+
+/**Function********************************************************************
+
+ Synopsis [Pushes a variable in the order down to position "level."]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+pushDown(
+ DdHalfWord * order,
+ int j,
+ int level)
+{
+ int i;
+ DdHalfWord tmp;
+
+ tmp = order[j];
+ for (i = j; i < level; i++) {
+ order[i] = order[i+1];
+ }
+ order[level] = tmp;
+ return;
+
+} /* end of pushDown */
+
+
+/**Function********************************************************************
+
+ Synopsis [Gathers symmetry information.]
+
+ Description [Translates the symmetry information stored in the next
+ field of each subtable from level to indices. This procedure is called
+ immediately after symmetric sifting, so that the next fields are correct.
+ By translating this informaton in terms of indices, we make it independent
+ of subsequent reorderings. The format used is that of the next fields:
+ a circular list where each variable points to the next variable in the
+ same symmetry group. Only the entries between lower and upper are
+ considered. The procedure returns a pointer to an array
+ holding the symmetry information if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [checkSymmInfo]
+
+******************************************************************************/
+static DdHalfWord *
+initSymmInfo(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int level, index, next, nextindex;
+ DdHalfWord *symmInfo;
+
+ symmInfo = ALLOC(DdHalfWord, table->size);
+ if (symmInfo == NULL) return(NULL);
+
+ for (level = lower; level <= upper; level++) {
+ index = table->invperm[level];
+ next = table->subtables[level].next;
+ nextindex = table->invperm[next];
+ symmInfo[index] = nextindex;
+ }
+ return(symmInfo);
+
+} /* end of initSymmInfo */
+
+
+/**Function********************************************************************
+
+ Synopsis [Check symmetry condition.]
+
+ Description [Returns 1 if a variable is the one with the highest index
+ among those belonging to a symmetry group that are in the top part of
+ the BDD. The top part is given by level.]
+
+ SideEffects [None]
+
+ SeeAlso [initSymmInfo]
+
+******************************************************************************/
+static int
+checkSymmInfo(
+ DdManager * table,
+ DdHalfWord * symmInfo,
+ int index,
+ int level)
+{
+ int i;
+
+ i = symmInfo[index];
+ while (i != index) {
+ if (index < i && table->perm[i] <= level)
+ return(0);
+ i = symmInfo[i];
+ }
+ return(1);
+
+} /* end of checkSymmInfo */
+
diff --git a/src/bdd/cudd/cuddExport.c b/src/bdd/cudd/cuddExport.c
new file mode 100644
index 00000000..d7b9645b
--- /dev/null
+++ b/src/bdd/cudd/cuddExport.c
@@ -0,0 +1,1289 @@
+/**CFile***********************************************************************
+
+ FileName [cuddExport.c]
+
+ PackageName [cudd]
+
+ Synopsis [Export functions.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_DumpBlif()
+ <li> Cudd_DumpBlifBody()
+ <li> Cudd_DumpDot()
+ <li> Cudd_DumpDaVinci()
+ <li> Cudd_DumpDDcal()
+ <li> Cudd_DumpFactoredForm()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> ddDoDumpBlif()
+ <li> ddDoDumpDaVinci()
+ <li> ddDoDumpDDcal()
+ <li> ddDoDumpFactoredForm()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddExport.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int ddDoDumpBlif ARGS((DdManager *dd, DdNode *f, FILE *fp, st_table *visited, char **names));
+static int ddDoDumpDaVinci ARGS((DdManager *dd, DdNode *f, FILE *fp, st_table *visited, char **names, long mask));
+static int ddDoDumpDDcal ARGS((DdManager *dd, DdNode *f, FILE *fp, st_table *visited, char **names, long mask));
+static int ddDoDumpFactoredForm ARGS((DdManager *dd, DdNode *f, FILE *fp, char **names));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Writes a blif file representing the argument BDDs.]
+
+ Description [Writes a blif file representing the argument BDDs as a
+ network of multiplexers. One multiplexer is written for each BDD
+ node. It returns 1 in case of success; 0 otherwise (e.g.,
+ out-of-memory, file system full, or an ADD with constants different
+ from 0 and 1). Cudd_DumpBlif does not close the file: This is the
+ caller responsibility. Cudd_DumpBlif uses a minimal unique subset of
+ the hexadecimal address of a node as name for it. If the argument
+ inames is non-null, it is assumed to hold the pointers to the names
+ of the inputs. Similarly for onames.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DumpBlifBody Cudd_DumpDot Cudd_PrintDebug Cudd_DumpDDcal
+ Cudd_DumpDaVinci Cudd_DumpFactoredForm]
+
+******************************************************************************/
+int
+Cudd_DumpBlif(
+ DdManager * dd /* manager */,
+ int n /* number of output nodes to be dumped */,
+ DdNode ** f /* array of output nodes to be dumped */,
+ char ** inames /* array of input names (or NULL) */,
+ char ** onames /* array of output names (or NULL) */,
+ char * mname /* model name (or NULL) */,
+ FILE * fp /* pointer to the dump file */)
+{
+ DdNode *support = NULL;
+ DdNode *scan;
+ int *sorted = NULL;
+ int nvars = dd->size;
+ int retval;
+ int i;
+
+ /* Build a bit array with the support of f. */
+ sorted = ALLOC(int,nvars);
+ if (sorted == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ goto failure;
+ }
+ for (i = 0; i < nvars; i++) sorted[i] = 0;
+
+ /* Take the union of the supports of each output function. */
+ support = Cudd_VectorSupport(dd,f,n);
+ if (support == NULL) goto failure;
+ cuddRef(support);
+ scan = support;
+ while (!cuddIsConstant(scan)) {
+ sorted[scan->index] = 1;
+ scan = cuddT(scan);
+ }
+ Cudd_RecursiveDeref(dd,support);
+ support = NULL; /* so that we do not try to free it in case of failure */
+
+ /* Write the header (.model .inputs .outputs). */
+ if (mname == NULL) {
+ retval = fprintf(fp,".model DD\n.inputs");
+ } else {
+ retval = fprintf(fp,".model %s\n.inputs",mname);
+ }
+ if (retval == EOF) return(0);
+
+ /* Write the input list by scanning the support array. */
+ for (i = 0; i < nvars; i++) {
+ if (sorted[i]) {
+ if (inames == NULL) {
+ retval = fprintf(fp," %d", i);
+ } else {
+ retval = fprintf(fp," %s", inames[i]);
+ }
+ if (retval == EOF) goto failure;
+ }
+ }
+ FREE(sorted);
+ sorted = NULL;
+
+ /* Write the .output line. */
+ retval = fprintf(fp,"\n.outputs");
+ if (retval == EOF) goto failure;
+ for (i = 0; i < n; i++) {
+ if (onames == NULL) {
+ retval = fprintf(fp," f%d", i);
+ } else {
+ retval = fprintf(fp," %s", onames[i]);
+ }
+ if (retval == EOF) goto failure;
+ }
+ retval = fprintf(fp,"\n");
+ if (retval == EOF) goto failure;
+
+ retval = Cudd_DumpBlifBody(dd, n, f, inames, onames, fp);
+ if (retval == 0) goto failure;
+
+ /* Write trailer and return. */
+ retval = fprintf(fp,".end\n");
+ if (retval == EOF) goto failure;
+
+ return(1);
+
+failure:
+ if (sorted != NULL) FREE(sorted);
+ if (support != NULL) Cudd_RecursiveDeref(dd,support);
+ return(0);
+
+} /* end of Cudd_DumpBlif */
+
+
+/**Function********************************************************************
+
+ Synopsis [Writes a blif body representing the argument BDDs.]
+
+ Description [Writes a blif body representing the argument BDDs as a
+ network of multiplexers. One multiplexer is written for each BDD
+ node. It returns 1 in case of success; 0 otherwise (e.g.,
+ out-of-memory, file system full, or an ADD with constants different
+ from 0 and 1). Cudd_DumpBlif does not close the file: This is the
+ caller responsibility. Cudd_DumpBlif uses a minimal unique subset of
+ the hexadecimal address of a node as name for it. If the argument
+ inames is non-null, it is assumed to hold the pointers to the names
+ of the inputs. Similarly for onames. This function prints out only
+ .names part.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DumpDot Cudd_PrintDebug Cudd_DumpDDcal
+ Cudd_DumpDaVinci Cudd_DumpFactoredForm]
+
+******************************************************************************/
+int
+Cudd_DumpBlifBody(
+ DdManager * dd /* manager */,
+ int n /* number of output nodes to be dumped */,
+ DdNode ** f /* array of output nodes to be dumped */,
+ char ** inames /* array of input names (or NULL) */,
+ char ** onames /* array of output names (or NULL) */,
+ FILE * fp /* pointer to the dump file */)
+{
+ st_table *visited = NULL;
+ int retval;
+ int i;
+
+ /* Initialize symbol table for visited nodes. */
+ visited = st_init_table(st_ptrcmp, st_ptrhash);
+ if (visited == NULL) goto failure;
+
+ /* Call the function that really gets the job done. */
+ for (i = 0; i < n; i++) {
+ retval = ddDoDumpBlif(dd,Cudd_Regular(f[i]),fp,visited,inames);
+ if (retval == 0) goto failure;
+ }
+
+ /* To account for the possible complement on the root,
+ ** we put either a buffer or an inverter at the output of
+ ** the multiplexer representing the top node.
+ */
+ for (i = 0; i < n; i++) {
+ if (onames == NULL) {
+ retval = fprintf(fp,
+#if SIZEOF_VOID_P == 8
+ ".names %lx f%d\n", (unsigned long) f[i] / (unsigned long) sizeof(DdNode), i);
+#else
+ ".names %x f%d\n", (unsigned) f[i] / (unsigned) sizeof(DdNode), i);
+#endif
+ } else {
+ retval = fprintf(fp,
+#if SIZEOF_VOID_P == 8
+ ".names %lx %s\n", (unsigned long) f[i] / (unsigned long) sizeof(DdNode), onames[i]);
+#else
+ ".names %x %s\n", (unsigned) f[i] / (unsigned) sizeof(DdNode), onames[i]);
+#endif
+ }
+ if (retval == EOF) goto failure;
+ if (Cudd_IsComplement(f[i])) {
+ retval = fprintf(fp,"0 1\n");
+ } else {
+ retval = fprintf(fp,"1 1\n");
+ }
+ if (retval == EOF) goto failure;
+ }
+
+ st_free_table(visited);
+ return(1);
+
+failure:
+ if (visited != NULL) st_free_table(visited);
+ return(0);
+
+} /* end of Cudd_DumpBlifBody */
+
+
+/**Function********************************************************************
+
+ Synopsis [Writes a dot file representing the argument DDs.]
+
+ Description [Writes a file representing the argument DDs in a format
+ suitable for the graph drawing program dot.
+ It returns 1 in case of success; 0 otherwise (e.g., out-of-memory,
+ file system full).
+ Cudd_DumpDot does not close the file: This is the caller
+ responsibility. Cudd_DumpDot uses a minimal unique subset of the
+ hexadecimal address of a node as name for it.
+ If the argument inames is non-null, it is assumed to hold the pointers
+ to the names of the inputs. Similarly for onames.
+ Cudd_DumpDot uses the following convention to draw arcs:
+ <ul>
+ <li> solid line: THEN arcs;
+ <li> dotted line: complement arcs;
+ <li> dashed line: regular ELSE arcs.
+ </ul>
+ The dot options are chosen so that the drawing fits on a letter-size
+ sheet.
+ ]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DumpBlif Cudd_PrintDebug Cudd_DumpDDcal
+ Cudd_DumpDaVinci Cudd_DumpFactoredForm]
+
+******************************************************************************/
+int
+Cudd_DumpDot(
+ DdManager * dd /* manager */,
+ int n /* number of output nodes to be dumped */,
+ DdNode ** f /* array of output nodes to be dumped */,
+ char ** inames /* array of input names (or NULL) */,
+ char ** onames /* array of output names (or NULL) */,
+ FILE * fp /* pointer to the dump file */)
+{
+ DdNode *support = NULL;
+ DdNode *scan;
+ int *sorted = NULL;
+ int nvars = dd->size;
+ st_table *visited = NULL;
+ st_generator *gen = NULL;
+ int retval;
+ int i, j;
+ int slots;
+ DdNodePtr *nodelist;
+ long refAddr, diff, mask;
+
+ /* Build a bit array with the support of f. */
+ sorted = ALLOC(int,nvars);
+ if (sorted == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ goto failure;
+ }
+ for (i = 0; i < nvars; i++) sorted[i] = 0;
+
+ /* Take the union of the supports of each output function. */
+ support = Cudd_VectorSupport(dd,f,n);
+ if (support == NULL) goto failure;
+ cuddRef(support);
+ scan = support;
+ while (!cuddIsConstant(scan)) {
+ sorted[scan->index] = 1;
+ scan = cuddT(scan);
+ }
+ Cudd_RecursiveDeref(dd,support);
+ support = NULL; /* so that we do not try to free it in case of failure */
+
+ /* Initialize symbol table for visited nodes. */
+ visited = st_init_table(st_ptrcmp, st_ptrhash);
+ if (visited == NULL) goto failure;
+
+ /* Collect all the nodes of this DD in the symbol table. */
+ for (i = 0; i < n; i++) {
+ retval = cuddCollectNodes(Cudd_Regular(f[i]),visited);
+ if (retval == 0) goto failure;
+ }
+
+ /* Find how many most significant hex digits are identical
+ ** in the addresses of all the nodes. Build a mask based
+ ** on this knowledge, so that digits that carry no information
+ ** will not be printed. This is done in two steps.
+ ** 1. We scan the symbol table to find the bits that differ
+ ** in at least 2 addresses.
+ ** 2. We choose one of the possible masks. There are 8 possible
+ ** masks for 32-bit integer, and 16 possible masks for 64-bit
+ ** integers.
+ */
+
+ /* Find the bits that are different. */
+ refAddr = (long) Cudd_Regular(f[0]);
+ diff = 0;
+ gen = st_init_gen(visited);
+ if (gen == NULL) goto failure;
+ while (st_gen(gen, (char **) &scan, NULL)) {
+ diff |= refAddr ^ (long) scan;
+ }
+ st_free_gen(gen); gen = NULL;
+
+ /* Choose the mask. */
+ for (i = 0; (unsigned) i < 8 * sizeof(long); i += 4) {
+ mask = (1 << i) - 1;
+ if (diff <= mask) break;
+ }
+
+ /* Write the header and the global attributes. */
+ retval = fprintf(fp,"digraph \"DD\" {\n");
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,
+ "size = \"7.5,10\"\ncenter = true;\nedge [dir = none];\n");
+ if (retval == EOF) return(0);
+
+ /* Write the input name subgraph by scanning the support array. */
+ retval = fprintf(fp,"{ node [shape = plaintext];\n");
+ if (retval == EOF) goto failure;
+ retval = fprintf(fp," edge [style = invis];\n");
+ if (retval == EOF) goto failure;
+ /* We use a name ("CONST NODES") with an embedded blank, because
+ ** it is unlikely to appear as an input name.
+ */
+ retval = fprintf(fp," \"CONST NODES\" [style = invis];\n");
+ if (retval == EOF) goto failure;
+ for (i = 0; i < nvars; i++) {
+ if (sorted[dd->invperm[i]]) {
+ if (inames == NULL || inames[dd->invperm[i]] == NULL) {
+ retval = fprintf(fp,"\" %d \" -> ", dd->invperm[i]);
+ } else {
+ retval = fprintf(fp,"\" %s \" -> ", inames[dd->invperm[i]]);
+ }
+ if (retval == EOF) goto failure;
+ }
+ }
+ retval = fprintf(fp,"\"CONST NODES\"; \n}\n");
+ if (retval == EOF) goto failure;
+
+ /* Write the output node subgraph. */
+ retval = fprintf(fp,"{ rank = same; node [shape = box]; edge [style = invis];\n");
+ if (retval == EOF) goto failure;
+ for (i = 0; i < n; i++) {
+ if (onames == NULL) {
+ retval = fprintf(fp,"\"F%d\"", i);
+ } else {
+ retval = fprintf(fp,"\" %s \"", onames[i]);
+ }
+ if (retval == EOF) goto failure;
+ if (i == n - 1) {
+ retval = fprintf(fp,"; }\n");
+ } else {
+ retval = fprintf(fp," -> ");
+ }
+ if (retval == EOF) goto failure;
+ }
+
+ /* Write rank info: All nodes with the same index have the same rank. */
+ for (i = 0; i < nvars; i++) {
+ if (sorted[dd->invperm[i]]) {
+ retval = fprintf(fp,"{ rank = same; ");
+ if (retval == EOF) goto failure;
+ if (inames == NULL || inames[dd->invperm[i]] == NULL) {
+ retval = fprintf(fp,"\" %d \";\n", dd->invperm[i]);
+ } else {
+ retval = fprintf(fp,"\" %s \";\n", inames[dd->invperm[i]]);
+ }
+ if (retval == EOF) goto failure;
+ nodelist = dd->subtables[i].nodelist;
+ slots = dd->subtables[i].slots;
+ for (j = 0; j < slots; j++) {
+ scan = nodelist[j];
+ while (scan != NULL) {
+ if (st_is_member(visited,(char *) scan)) {
+ retval = fprintf(fp,"\"%lx\";\n", (mask & (long) scan) / sizeof(DdNode));
+ if (retval == EOF) goto failure;
+ }
+ scan = scan->next;
+ }
+ }
+ retval = fprintf(fp,"}\n");
+ if (retval == EOF) goto failure;
+ }
+ }
+
+ /* All constants have the same rank. */
+ retval = fprintf(fp,
+ "{ rank = same; \"CONST NODES\";\n{ node [shape = box]; ");
+ if (retval == EOF) goto failure;
+ nodelist = dd->constants.nodelist;
+ slots = dd->constants.slots;
+ for (j = 0; j < slots; j++) {
+ scan = nodelist[j];
+ while (scan != NULL) {
+ if (st_is_member(visited,(char *) scan)) {
+ retval = fprintf(fp,"\"%lx\";\n", (mask & (long) scan) / sizeof(DdNode));
+ if (retval == EOF) goto failure;
+ }
+ scan = scan->next;
+ }
+ }
+ retval = fprintf(fp,"}\n}\n");
+ if (retval == EOF) goto failure;
+
+ /* Write edge info. */
+ /* Edges from the output nodes. */
+ for (i = 0; i < n; i++) {
+ if (onames == NULL) {
+ retval = fprintf(fp,"\"F%d\"", i);
+ } else {
+ retval = fprintf(fp,"\" %s \"", onames[i]);
+ }
+ if (retval == EOF) goto failure;
+ /* Account for the possible complement on the root. */
+ if (Cudd_IsComplement(f[i])) {
+ retval = fprintf(fp," -> \"%lx\" [style = dotted];\n",
+ (mask & (long) f[i]) / sizeof(DdNode));
+ } else {
+ retval = fprintf(fp," -> \"%lx\" [style = solid];\n",
+ (mask & (long) f[i]) / sizeof(DdNode));
+ }
+ if (retval == EOF) goto failure;
+ }
+
+ /* Edges from internal nodes. */
+ for (i = 0; i < nvars; i++) {
+ if (sorted[dd->invperm[i]]) {
+ nodelist = dd->subtables[i].nodelist;
+ slots = dd->subtables[i].slots;
+ for (j = 0; j < slots; j++) {
+ scan = nodelist[j];
+ while (scan != NULL) {
+ if (st_is_member(visited,(char *) scan)) {
+ retval = fprintf(fp,
+ "\"%lx\" -> \"%lx\";\n",
+ (mask & (long) scan) / sizeof(DdNode),
+ (mask & (long) cuddT(scan)) / sizeof(DdNode));
+ if (retval == EOF) goto failure;
+ if (Cudd_IsComplement(cuddE(scan))) {
+ retval = fprintf(fp,
+ "\"%lx\" -> \"%lx\" [style = dotted];\n",
+ (mask & (long) scan) / sizeof(DdNode),
+ (mask & (long) cuddE(scan)) / sizeof(DdNode));
+ } else {
+ retval = fprintf(fp,
+ "\"%lx\" -> \"%lx\" [style = dashed];\n",
+ (mask & (long) scan) / sizeof(DdNode),
+ (mask & (long) cuddE(scan)) / sizeof(DdNode));
+ }
+ if (retval == EOF) goto failure;
+ }
+ scan = scan->next;
+ }
+ }
+ }
+ }
+
+ /* Write constant labels. */
+ nodelist = dd->constants.nodelist;
+ slots = dd->constants.slots;
+ for (j = 0; j < slots; j++) {
+ scan = nodelist[j];
+ while (scan != NULL) {
+ if (st_is_member(visited,(char *) scan)) {
+ retval = fprintf(fp,"\"%lx\" [label = \"%g\"];\n",
+ (mask & (long) scan) / sizeof(DdNode), cuddV(scan));
+ if (retval == EOF) goto failure;
+ }
+ scan = scan->next;
+ }
+ }
+
+ /* Write trailer and return. */
+ retval = fprintf(fp,"}\n");
+ if (retval == EOF) goto failure;
+
+ st_free_table(visited);
+ FREE(sorted);
+ return(1);
+
+failure:
+ if (sorted != NULL) FREE(sorted);
+ if (support != NULL) Cudd_RecursiveDeref(dd,support);
+ if (visited != NULL) st_free_table(visited);
+ return(0);
+
+} /* end of Cudd_DumpDot */
+
+
+/**Function********************************************************************
+
+ Synopsis [Writes a daVinci file representing the argument BDDs.]
+
+ Description [Writes a daVinci file representing the argument BDDs.
+ It returns 1 in case of success; 0 otherwise (e.g., out-of-memory or
+ file system full). Cudd_DumpDaVinci does not close the file: This
+ is the caller responsibility. Cudd_DumpDaVinci uses a minimal unique
+ subset of the hexadecimal address of a node as name for it. If the
+ argument inames is non-null, it is assumed to hold the pointers to
+ the names of the inputs. Similarly for onames.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DumpDot Cudd_PrintDebug Cudd_DumpBlif Cudd_DumpDDcal
+ Cudd_DumpFactoredForm]
+
+******************************************************************************/
+int
+Cudd_DumpDaVinci(
+ DdManager * dd /* manager */,
+ int n /* number of output nodes to be dumped */,
+ DdNode ** f /* array of output nodes to be dumped */,
+ char ** inames /* array of input names (or NULL) */,
+ char ** onames /* array of output names (or NULL) */,
+ FILE * fp /* pointer to the dump file */)
+{
+ DdNode *support = NULL;
+ DdNode *scan;
+ st_table *visited = NULL;
+ int retval;
+ int i;
+ st_generator *gen;
+ long refAddr, diff, mask;
+
+ /* Initialize symbol table for visited nodes. */
+ visited = st_init_table(st_ptrcmp, st_ptrhash);
+ if (visited == NULL) goto failure;
+
+ /* Collect all the nodes of this DD in the symbol table. */
+ for (i = 0; i < n; i++) {
+ retval = cuddCollectNodes(Cudd_Regular(f[i]),visited);
+ if (retval == 0) goto failure;
+ }
+
+ /* Find how many most significant hex digits are identical
+ ** in the addresses of all the nodes. Build a mask based
+ ** on this knowledge, so that digits that carry no information
+ ** will not be printed. This is done in two steps.
+ ** 1. We scan the symbol table to find the bits that differ
+ ** in at least 2 addresses.
+ ** 2. We choose one of the possible masks. There are 8 possible
+ ** masks for 32-bit integer, and 16 possible masks for 64-bit
+ ** integers.
+ */
+
+ /* Find the bits that are different. */
+ refAddr = (long) Cudd_Regular(f[0]);
+ diff = 0;
+ gen = st_init_gen(visited);
+ while (st_gen(gen, (char **) &scan, NULL)) {
+ diff |= refAddr ^ (long) scan;
+ }
+ st_free_gen(gen);
+
+ /* Choose the mask. */
+ for (i = 0; (unsigned) i < 8 * sizeof(long); i += 4) {
+ mask = (1 << i) - 1;
+ if (diff <= mask) break;
+ }
+ st_free_table(visited);
+
+ /* Initialize symbol table for visited nodes. */
+ visited = st_init_table(st_ptrcmp, st_ptrhash);
+ if (visited == NULL) goto failure;
+
+ retval = fprintf(fp, "[");
+ if (retval == EOF) goto failure;
+ /* Call the function that really gets the job done. */
+ for (i = 0; i < n; i++) {
+ if (onames == NULL) {
+ retval = fprintf(fp,
+ "l(\"f%d\",n(\"root\",[a(\"OBJECT\",\"f%d\")],",
+ i,i);
+ } else {
+ retval = fprintf(fp,
+ "l(\"%s\",n(\"root\",[a(\"OBJECT\",\"%s\")],",
+ onames[i], onames[i]);
+ }
+ if (retval == EOF) goto failure;
+ retval = fprintf(fp, "[e(\"edge\",[a(\"EDGECOLOR\",\"%s\"),a(\"_DIR\",\"none\")],",
+ Cudd_IsComplement(f[i]) ? "red" : "blue");
+ if (retval == EOF) goto failure;
+ retval = ddDoDumpDaVinci(dd,Cudd_Regular(f[i]),fp,visited,inames,mask);
+ if (retval == 0) goto failure;
+ retval = fprintf(fp, ")]))%s", i == n-1 ? "" : ",");
+ if (retval == EOF) goto failure;
+ }
+
+ /* Write trailer and return. */
+ retval = fprintf(fp, "]\n");
+ if (retval == EOF) goto failure;
+
+ st_free_table(visited);
+ return(1);
+
+failure:
+ if (support != NULL) Cudd_RecursiveDeref(dd,support);
+ if (visited != NULL) st_free_table(visited);
+ return(0);
+
+} /* end of Cudd_DumpDaVinci */
+
+
+/**Function********************************************************************
+
+ Synopsis [Writes a DDcal file representing the argument BDDs.]
+
+ Description [Writes a DDcal file representing the argument BDDs.
+ It returns 1 in case of success; 0 otherwise (e.g., out-of-memory or
+ file system full). Cudd_DumpDDcal does not close the file: This
+ is the caller responsibility. Cudd_DumpDDcal uses a minimal unique
+ subset of the hexadecimal address of a node as name for it. If the
+ argument inames is non-null, it is assumed to hold the pointers to
+ the names of the inputs. Similarly for onames.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DumpDot Cudd_PrintDebug Cudd_DumpBlif Cudd_DumpDaVinci
+ Cudd_DumpFactoredForm]
+
+******************************************************************************/
+int
+Cudd_DumpDDcal(
+ DdManager * dd /* manager */,
+ int n /* number of output nodes to be dumped */,
+ DdNode ** f /* array of output nodes to be dumped */,
+ char ** inames /* array of input names (or NULL) */,
+ char ** onames /* array of output names (or NULL) */,
+ FILE * fp /* pointer to the dump file */)
+{
+ DdNode *support = NULL;
+ DdNode *scan;
+ int *sorted = NULL;
+ int nvars = dd->size;
+ st_table *visited = NULL;
+ int retval;
+ int i;
+ st_generator *gen;
+ long refAddr, diff, mask;
+
+ /* Initialize symbol table for visited nodes. */
+ visited = st_init_table(st_ptrcmp, st_ptrhash);
+ if (visited == NULL) goto failure;
+
+ /* Collect all the nodes of this DD in the symbol table. */
+ for (i = 0; i < n; i++) {
+ retval = cuddCollectNodes(Cudd_Regular(f[i]),visited);
+ if (retval == 0) goto failure;
+ }
+
+ /* Find how many most significant hex digits are identical
+ ** in the addresses of all the nodes. Build a mask based
+ ** on this knowledge, so that digits that carry no information
+ ** will not be printed. This is done in two steps.
+ ** 1. We scan the symbol table to find the bits that differ
+ ** in at least 2 addresses.
+ ** 2. We choose one of the possible masks. There are 8 possible
+ ** masks for 32-bit integer, and 16 possible masks for 64-bit
+ ** integers.
+ */
+
+ /* Find the bits that are different. */
+ refAddr = (long) Cudd_Regular(f[0]);
+ diff = 0;
+ gen = st_init_gen(visited);
+ while (st_gen(gen, (char **) &scan, NULL)) {
+ diff |= refAddr ^ (long) scan;
+ }
+ st_free_gen(gen);
+
+ /* Choose the mask. */
+ for (i = 0; (unsigned) i < 8 * sizeof(long); i += 4) {
+ mask = (1 << i) - 1;
+ if (diff <= mask) break;
+ }
+ st_free_table(visited);
+
+ /* Build a bit array with the support of f. */
+ sorted = ALLOC(int,nvars);
+ if (sorted == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ goto failure;
+ }
+ for (i = 0; i < nvars; i++) sorted[i] = 0;
+
+ /* Take the union of the supports of each output function. */
+ support = Cudd_VectorSupport(dd,f,n);
+ if (support == NULL) goto failure;
+ cuddRef(support);
+ scan = support;
+ while (!cuddIsConstant(scan)) {
+ sorted[scan->index] = 1;
+ scan = cuddT(scan);
+ }
+ Cudd_RecursiveDeref(dd,support);
+ support = NULL; /* so that we do not try to free it in case of failure */
+ for (i = 0; i < nvars; i++) {
+ if (sorted[dd->invperm[i]]) {
+ if (inames == NULL || inames[dd->invperm[i]] == NULL) {
+ retval = fprintf(fp,"v%d", dd->invperm[i]);
+ } else {
+ retval = fprintf(fp,"%s", inames[dd->invperm[i]]);
+ }
+ if (retval == EOF) goto failure;
+ }
+ retval = fprintf(fp,"%s", i == nvars - 1 ? "\n" : " * ");
+ if (retval == EOF) goto failure;
+ }
+ FREE(sorted);
+ sorted = NULL;
+
+ /* Initialize symbol table for visited nodes. */
+ visited = st_init_table(st_ptrcmp, st_ptrhash);
+ if (visited == NULL) goto failure;
+
+ /* Call the function that really gets the job done. */
+ for (i = 0; i < n; i++) {
+ retval = ddDoDumpDDcal(dd,Cudd_Regular(f[i]),fp,visited,inames,mask);
+ if (retval == 0) goto failure;
+ if (onames == NULL) {
+ retval = fprintf(fp, "f%d = ", i);
+ } else {
+ retval = fprintf(fp, "%s = ", onames[i]);
+ }
+ if (retval == EOF) goto failure;
+ retval = fprintf(fp, "n%lx%s\n",
+ ((long) f[i] & mask) / sizeof(DdNode),
+ Cudd_IsComplement(f[i]) ? "'" : "");
+ if (retval == EOF) goto failure;
+ }
+
+ /* Write trailer and return. */
+ retval = fprintf(fp, "[");
+ if (retval == EOF) goto failure;
+ for (i = 0; i < n; i++) {
+ if (onames == NULL) {
+ retval = fprintf(fp, "f%d", i);
+ } else {
+ retval = fprintf(fp, "%s", onames[i]);
+ }
+ retval = fprintf(fp, "%s", i == n-1 ? "" : " ");
+ if (retval == EOF) goto failure;
+ }
+ retval = fprintf(fp, "]\n");
+ if (retval == EOF) goto failure;
+
+ st_free_table(visited);
+ return(1);
+
+failure:
+ if (sorted != NULL) FREE(sorted);
+ if (support != NULL) Cudd_RecursiveDeref(dd,support);
+ if (visited != NULL) st_free_table(visited);
+ return(0);
+
+} /* end of Cudd_DumpDDcal */
+
+
+/**Function********************************************************************
+
+ Synopsis [Writes factored forms representing the argument BDDs.]
+
+ Description [Writes factored forms representing the argument BDDs.
+ The format of the factored form is the one used in the genlib files
+ for technology mapping in sis. It returns 1 in case of success; 0
+ otherwise (e.g., file system full). Cudd_DumpFactoredForm does not
+ close the file: This is the caller responsibility. Caution must be
+ exercised because a factored form may be exponentially larger than
+ the argument BDD. If the argument inames is non-null, it is assumed
+ to hold the pointers to the names of the inputs. Similarly for
+ onames.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DumpDot Cudd_PrintDebug Cudd_DumpBlif Cudd_DumpDaVinci
+ Cudd_DumpDDcal]
+
+******************************************************************************/
+int
+Cudd_DumpFactoredForm(
+ DdManager * dd /* manager */,
+ int n /* number of output nodes to be dumped */,
+ DdNode ** f /* array of output nodes to be dumped */,
+ char ** inames /* array of input names (or NULL) */,
+ char ** onames /* array of output names (or NULL) */,
+ FILE * fp /* pointer to the dump file */)
+{
+ int retval;
+ int i;
+
+ /* Call the function that really gets the job done. */
+ for (i = 0; i < n; i++) {
+ if (onames == NULL) {
+ retval = fprintf(fp, "f%d = ", i);
+ } else {
+ retval = fprintf(fp, "%s = ", onames[i]);
+ }
+ if (retval == EOF) return(0);
+ if (f[i] == DD_ONE(dd)) {
+ retval = fprintf(fp, "CONST1");
+ if (retval == EOF) return(0);
+ } else if (f[i] == Cudd_Not(DD_ONE(dd)) || f[i] == DD_ZERO(dd)) {
+ retval = fprintf(fp, "CONST0");
+ if (retval == EOF) return(0);
+ } else {
+ retval = fprintf(fp, "%s", Cudd_IsComplement(f[i]) ? "!(" : "");
+ if (retval == EOF) return(0);
+ retval = ddDoDumpFactoredForm(dd,Cudd_Regular(f[i]),fp,inames);
+ if (retval == 0) return(0);
+ retval = fprintf(fp, "%s", Cudd_IsComplement(f[i]) ? ")" : "");
+ if (retval == EOF) return(0);
+ }
+ retval = fprintf(fp, "%s", i == n-1 ? "" : "\n");
+ if (retval == EOF) return(0);
+ }
+
+ return(1);
+
+} /* end of Cudd_DumpFactoredForm */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_DumpBlif.]
+
+ Description [Performs the recursive step of Cudd_DumpBlif. Traverses
+ the BDD f and writes a multiplexer-network description to the file
+ pointed by fp in blif format. f is assumed to be a regular pointer
+ and ddDoDumpBlif guarantees this assumption in the recursive calls.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+ddDoDumpBlif(
+ DdManager * dd,
+ DdNode * f,
+ FILE * fp,
+ st_table * visited,
+ char ** names)
+{
+ DdNode *T, *E;
+ int retval;
+
+#ifdef DD_DEBUG
+ assert(!Cudd_IsComplement(f));
+#endif
+
+ /* If already visited, nothing to do. */
+ if (st_is_member(visited, (char *) f) == 1)
+ return(1);
+
+ /* Check for abnormal condition that should never happen. */
+ if (f == NULL)
+ return(0);
+
+ /* Mark node as visited. */
+ if (st_insert(visited, (char *) f, NULL) == ST_OUT_OF_MEM)
+ return(0);
+
+ /* Check for special case: If constant node, generate constant 1. */
+ if (f == DD_ONE(dd)) {
+#if SIZEOF_VOID_P == 8
+ retval = fprintf(fp, ".names %lx\n1\n",(unsigned long) f / (unsigned long) sizeof(DdNode));
+#else
+ retval = fprintf(fp, ".names %x\n1\n",(unsigned) f / (unsigned) sizeof(DdNode));
+#endif
+ if (retval == EOF) {
+ return(0);
+ } else {
+ return(1);
+ }
+ }
+
+ /* Check whether this is an ADD. We deal with 0-1 ADDs, but not
+ ** with the general case.
+ */
+ if (f == DD_ZERO(dd)) {
+#if SIZEOF_VOID_P == 8
+ retval = fprintf(fp, ".names %lx\n",(unsigned long) f / (unsigned long) sizeof(DdNode));
+#else
+ retval = fprintf(fp, ".names %x\n",(unsigned) f / (unsigned) sizeof(DdNode));
+#endif
+ if (retval == EOF) {
+ return(0);
+ } else {
+ return(1);
+ }
+ }
+ if (cuddIsConstant(f))
+ return(0);
+
+ /* Recursive calls. */
+ T = cuddT(f);
+ retval = ddDoDumpBlif(dd,T,fp,visited,names);
+ if (retval != 1) return(retval);
+ E = Cudd_Regular(cuddE(f));
+ retval = ddDoDumpBlif(dd,E,fp,visited,names);
+ if (retval != 1) return(retval);
+
+ /* Write multiplexer taking complement arc into account. */
+ if (names != NULL) {
+ retval = fprintf(fp,".names %s", names[f->index]);
+ } else {
+ retval = fprintf(fp,".names %d", f->index);
+ }
+ if (retval == EOF)
+ return(0);
+
+#if SIZEOF_VOID_P == 8
+ if (Cudd_IsComplement(cuddE(f))) {
+ retval = fprintf(fp," %lx %lx %lx\n11- 1\n0-0 1\n",
+ (unsigned long) T / (unsigned long) sizeof(DdNode),
+ (unsigned long) E / (unsigned long) sizeof(DdNode),
+ (unsigned long) f / (unsigned long) sizeof(DdNode));
+ } else {
+ retval = fprintf(fp," %lx %lx %lx\n11- 1\n0-1 1\n",
+ (unsigned long) T / (unsigned long) sizeof(DdNode),
+ (unsigned long) E / (unsigned long) sizeof(DdNode),
+ (unsigned long) f / (unsigned long) sizeof(DdNode));
+ }
+#else
+ if (Cudd_IsComplement(cuddE(f))) {
+ retval = fprintf(fp," %x %x %x\n11- 1\n0-0 1\n",
+ (unsigned) T / (unsigned) sizeof(DdNode),
+ (unsigned) E / (unsigned) sizeof(DdNode),
+ (unsigned) f / (unsigned) sizeof(DdNode));
+ } else {
+ retval = fprintf(fp," %x %x %x\n11- 1\n0-1 1\n",
+ (unsigned) T / (unsigned) sizeof(DdNode),
+ (unsigned) E / (unsigned) sizeof(DdNode),
+ (unsigned) f / (unsigned) sizeof(DdNode));
+ }
+#endif
+ if (retval == EOF) {
+ return(0);
+ } else {
+ return(1);
+ }
+
+} /* end of ddDoDumpBlif */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_DumpDaVinci.]
+
+ Description [Performs the recursive step of Cudd_DumpDaVinci. Traverses
+ the BDD f and writes a term expression to the file
+ pointed by fp in daVinci format. f is assumed to be a regular pointer
+ and ddDoDumpDaVinci guarantees this assumption in the recursive calls.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+ddDoDumpDaVinci(
+ DdManager * dd,
+ DdNode * f,
+ FILE * fp,
+ st_table * visited,
+ char ** names,
+ long mask)
+{
+ DdNode *T, *E;
+ int retval;
+ long id;
+
+#ifdef DD_DEBUG
+ assert(!Cudd_IsComplement(f));
+#endif
+
+ id = ((long) f & mask) / sizeof(DdNode);
+
+ /* If already visited, insert a reference. */
+ if (st_is_member(visited, (char *) f) == 1) {
+ retval = fprintf(fp,"r(\"%lx\")", id);
+ if (retval == EOF) {
+ return(0);
+ } else {
+ return(1);
+ }
+ }
+
+ /* Check for abnormal condition that should never happen. */
+ if (f == NULL)
+ return(0);
+
+ /* Mark node as visited. */
+ if (st_insert(visited, (char *) f, NULL) == ST_OUT_OF_MEM)
+ return(0);
+
+ /* Check for special case: If constant node, generate constant 1. */
+ if (Cudd_IsConstant(f)) {
+ retval = fprintf(fp, "l(\"%lx\",n(\"constant\",[a(\"OBJECT\",\"%g\")],[]))", id, cuddV(f));
+ if (retval == EOF) {
+ return(0);
+ } else {
+ return(1);
+ }
+ }
+
+ /* Recursive calls. */
+ if (names != NULL) {
+ retval = fprintf(fp,
+ "l(\"%lx\",n(\"internal\",[a(\"OBJECT\",\"%s\"),",
+ id, names[f->index]);
+ } else {
+ retval = fprintf(fp,
+ "l(\"%lx\",n(\"internal\",[a(\"OBJECT\",\"%d\"),",
+ id, f->index);
+ }
+ retval = fprintf(fp, "a(\"_GO\",\"ellipse\")],[e(\"then\",[a(\"EDGECOLOR\",\"blue\"),a(\"_DIR\",\"none\")],");
+ if (retval == EOF) return(0);
+ T = cuddT(f);
+ retval = ddDoDumpDaVinci(dd,T,fp,visited,names,mask);
+ if (retval != 1) return(retval);
+ retval = fprintf(fp, "),e(\"else\",[a(\"EDGECOLOR\",\"%s\"),a(\"_DIR\",\"none\")],",
+ Cudd_IsComplement(cuddE(f)) ? "red" : "green");
+ if (retval == EOF) return(0);
+ E = Cudd_Regular(cuddE(f));
+ retval = ddDoDumpDaVinci(dd,E,fp,visited,names,mask);
+ if (retval != 1) return(retval);
+
+ retval = fprintf(fp,")]))");
+ if (retval == EOF) {
+ return(0);
+ } else {
+ return(1);
+ }
+
+} /* end of ddDoDumpDaVinci */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_DumpDDcal.]
+
+ Description [Performs the recursive step of Cudd_DumpDDcal. Traverses
+ the BDD f and writes a line for each node to the file
+ pointed by fp in DDcal format. f is assumed to be a regular pointer
+ and ddDoDumpDDcal guarantees this assumption in the recursive calls.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+ddDoDumpDDcal(
+ DdManager * dd,
+ DdNode * f,
+ FILE * fp,
+ st_table * visited,
+ char ** names,
+ long mask)
+{
+ DdNode *T, *E;
+ int retval;
+ long id, idT, idE;
+
+#ifdef DD_DEBUG
+ assert(!Cudd_IsComplement(f));
+#endif
+
+ id = ((long) f & mask) / sizeof(DdNode);
+
+ /* If already visited, do nothing. */
+ if (st_is_member(visited, (char *) f) == 1) {
+ return(1);
+ }
+
+ /* Check for abnormal condition that should never happen. */
+ if (f == NULL)
+ return(0);
+
+ /* Mark node as visited. */
+ if (st_insert(visited, (char *) f, NULL) == ST_OUT_OF_MEM)
+ return(0);
+
+ /* Check for special case: If constant node, assign constant. */
+ if (Cudd_IsConstant(f)) {
+ if (f != DD_ONE(dd) && f != DD_ZERO(dd))
+ return(0);
+ retval = fprintf(fp, "n%lx = %g\n", id, cuddV(f));
+ if (retval == EOF) {
+ return(0);
+ } else {
+ return(1);
+ }
+ }
+
+ /* Recursive calls. */
+ T = cuddT(f);
+ retval = ddDoDumpDDcal(dd,T,fp,visited,names,mask);
+ if (retval != 1) return(retval);
+ E = Cudd_Regular(cuddE(f));
+ retval = ddDoDumpDDcal(dd,E,fp,visited,names,mask);
+ if (retval != 1) return(retval);
+ idT = ((long) T & mask) / sizeof(DdNode);
+ idE = ((long) E & mask) / sizeof(DdNode);
+ if (names != NULL) {
+ retval = fprintf(fp, "n%lx = %s * n%lx + %s' * n%lx%s\n",
+ id, names[f->index], idT, names[f->index],
+ idE, Cudd_IsComplement(cuddE(f)) ? "'" : "");
+ } else {
+ retval = fprintf(fp, "n%lx = v%d * n%lx + v%d' * n%lx%s\n",
+ id, f->index, idT, f->index,
+ idE, Cudd_IsComplement(cuddE(f)) ? "'" : "");
+ }
+ if (retval == EOF) {
+ return(0);
+ } else {
+ return(1);
+ }
+
+} /* end of ddDoDumpDDcal */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_DumpFactoredForm.]
+
+ Description [Performs the recursive step of
+ Cudd_DumpFactoredForm. Traverses the BDD f and writes a factored
+ form for each node to the file pointed by fp in terms of the
+ factored forms of the children. Constants are propagated, and
+ absorption is applied. f is assumed to be a regular pointer and
+ ddDoDumpFActoredForm guarantees this assumption in the recursive
+ calls.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DumpFactoredForm]
+
+******************************************************************************/
+static int
+ddDoDumpFactoredForm(
+ DdManager * dd,
+ DdNode * f,
+ FILE * fp,
+ char ** names)
+{
+ DdNode *T, *E;
+ int retval;
+
+#ifdef DD_DEBUG
+ assert(!Cudd_IsComplement(f));
+ assert(!Cudd_IsConstant(f));
+#endif
+
+ /* Check for abnormal condition that should never happen. */
+ if (f == NULL)
+ return(0);
+
+ /* Recursive calls. */
+ T = cuddT(f);
+ E = cuddE(f);
+ if (T != DD_ZERO(dd)) {
+ if (E != DD_ONE(dd)) {
+ if (names != NULL) {
+ retval = fprintf(fp, "%s", names[f->index]);
+ } else {
+ retval = fprintf(fp, "x%d", f->index);
+ }
+ if (retval == EOF) return(0);
+ }
+ if (T != DD_ONE(dd)) {
+ retval = fprintf(fp, "%s(", E != DD_ONE(dd) ? " * " : "");
+ if (retval == EOF) return(0);
+ retval = ddDoDumpFactoredForm(dd,T,fp,names);
+ if (retval != 1) return(retval);
+ retval = fprintf(fp, ")");
+ if (retval == EOF) return(0);
+ }
+ if (E == Cudd_Not(DD_ONE(dd)) || E == DD_ZERO(dd)) return(1);
+ retval = fprintf(fp, " + ");
+ if (retval == EOF) return(0);
+ }
+ E = Cudd_Regular(E);
+ if (T != DD_ONE(dd)) {
+ if (names != NULL) {
+ retval = fprintf(fp, "!%s", names[f->index]);
+ } else {
+ retval = fprintf(fp, "!x%d", f->index);
+ }
+ if (retval == EOF) return(0);
+ }
+ if (E != DD_ONE(dd)) {
+ retval = fprintf(fp, "%s%s(", T != DD_ONE(dd) ? " * " : "",
+ E != cuddE(f) ? "!" : "");
+ if (retval == EOF) return(0);
+ retval = ddDoDumpFactoredForm(dd,E,fp,names);
+ if (retval != 1) return(retval);
+ retval = fprintf(fp, ")");
+ if (retval == EOF) return(0);
+ }
+ return(1);
+
+} /* end of ddDoDumpFactoredForm */
+
diff --git a/src/bdd/cudd/cuddGenCof.c b/src/bdd/cudd/cuddGenCof.c
new file mode 100644
index 00000000..59ae55d7
--- /dev/null
+++ b/src/bdd/cudd/cuddGenCof.c
@@ -0,0 +1,1968 @@
+/**CFile***********************************************************************
+
+ FileName [cuddGenCof.c]
+
+ PackageName [cudd]
+
+ Synopsis [Generalized cofactors for BDDs and ADDs.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_bddConstrain()
+ <li> Cudd_bddRestrict()
+ <li> Cudd_addConstrain()
+ <li> Cudd_bddConstrainDecomp()
+ <li> Cudd_addRestrict()
+ <li> Cudd_bddCharToVect()
+ <li> Cudd_bddLICompaction()
+ <li> Cudd_bddSqueeze()
+ <li> Cudd_SubsetCompress()
+ <li> Cudd_SupersetCompress()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddBddConstrainRecur()
+ <li> cuddBddRestrictRecur()
+ <li> cuddAddConstrainRecur()
+ <li> cuddAddRestrictRecur()
+ <li> cuddBddLICompaction()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> cuddBddConstrainDecomp()
+ <li> cuddBddCharToVect()
+ <li> cuddBddLICMarkEdges()
+ <li> cuddBddLICBuildResult()
+ <li> cuddBddSqueeze()
+ </ul>
+ ]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/* Codes for edge markings in Cudd_bddLICompaction. The codes are defined
+** so that they can be bitwise ORed to implement the code priority scheme.
+*/
+#define DD_LIC_DC 0
+#define DD_LIC_1 1
+#define DD_LIC_0 2
+#define DD_LIC_NL 3
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/* Key for the cache used in the edge marking phase. */
+typedef struct MarkCacheKey {
+ DdNode *f;
+ DdNode *c;
+} MarkCacheKey;
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddGenCof.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int cuddBddConstrainDecomp ARGS((DdManager *dd, DdNode *f, DdNode **decomp));
+static DdNode * cuddBddCharToVect ARGS((DdManager *dd, DdNode *f, DdNode *x));
+static int cuddBddLICMarkEdges ARGS((DdManager *dd, DdNode *f, DdNode *c, st_table *table, st_table *cache));
+static DdNode * cuddBddLICBuildResult ARGS((DdManager *dd, DdNode *f, st_table *cache, st_table *table));
+static int MarkCacheHash ARGS((char *ptr, int modulus));
+static int MarkCacheCompare ARGS((const char *ptr1, const char *ptr2));
+static enum st_retval MarkCacheCleanUp ARGS((char *key, char *value, char *arg));
+static DdNode * cuddBddSqueeze ARGS((DdManager *dd, DdNode *l, DdNode *u));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes f constrain c.]
+
+ Description [Computes f constrain c (f @ c).
+ Uses a canonical form: (f' @ c) = ( f @ c)'. (Note: this is not true
+ for c.) List of special cases:
+ <ul>
+ <li> f @ 0 = 0
+ <li> f @ 1 = f
+ <li> 0 @ c = 0
+ <li> 1 @ c = 1
+ <li> f @ f = 1
+ <li> f @ f'= 0
+ </ul>
+ Returns a pointer to the result if successful; NULL otherwise. Note that if
+ F=(f1,...,fn) and reordering takes place while computing F @ c, then the
+ image restriction property (Img(F,c) = Img(F @ c)) is lost.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddRestrict Cudd_addConstrain]
+
+******************************************************************************/
+DdNode *
+Cudd_bddConstrain(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * c)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddConstrainRecur(dd,f,c);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddConstrain */
+
+
+/**Function********************************************************************
+
+ Synopsis [BDD restrict according to Coudert and Madre's algorithm
+ (ICCAD90).]
+
+ Description [BDD restrict according to Coudert and Madre's algorithm
+ (ICCAD90). Returns the restricted BDD if successful; otherwise NULL.
+ If application of restrict results in a BDD larger than the input
+ BDD, the input BDD is returned.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddConstrain Cudd_addRestrict]
+
+******************************************************************************/
+DdNode *
+Cudd_bddRestrict(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * c)
+{
+ DdNode *suppF, *suppC, *commonSupport;
+ DdNode *cplus, *res;
+ int retval;
+ int sizeF, sizeRes;
+
+ /* Check terminal cases here to avoid computing supports in trivial cases.
+ ** This also allows us notto check later for the case c == 0, in which
+ ** there is no common support. */
+ if (c == Cudd_Not(DD_ONE(dd))) return(Cudd_Not(DD_ONE(dd)));
+ if (Cudd_IsConstant(f)) return(f);
+ if (f == c) return(DD_ONE(dd));
+ if (f == Cudd_Not(c)) return(Cudd_Not(DD_ONE(dd)));
+
+ /* Check if supports intersect. */
+ retval = Cudd_ClassifySupport(dd,f,c,&commonSupport,&suppF,&suppC);
+ if (retval == 0) {
+ return(NULL);
+ }
+ cuddRef(commonSupport); cuddRef(suppF); cuddRef(suppC);
+ Cudd_IterDerefBdd(dd,suppF);
+
+ if (commonSupport == DD_ONE(dd)) {
+ Cudd_IterDerefBdd(dd,commonSupport);
+ Cudd_IterDerefBdd(dd,suppC);
+ return(f);
+ }
+ Cudd_IterDerefBdd(dd,commonSupport);
+
+ /* Abstract from c the variables that do not appear in f. */
+ cplus = Cudd_bddExistAbstract(dd, c, suppC);
+ if (cplus == NULL) {
+ Cudd_IterDerefBdd(dd,suppC);
+ return(NULL);
+ }
+ cuddRef(cplus);
+ Cudd_IterDerefBdd(dd,suppC);
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddRestrictRecur(dd, f, cplus);
+ } while (dd->reordered == 1);
+ if (res == NULL) {
+ Cudd_IterDerefBdd(dd,cplus);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_IterDerefBdd(dd,cplus);
+ /* Make restric safe by returning the smaller of the input and the
+ ** result. */
+ sizeF = Cudd_DagSize(f);
+ sizeRes = Cudd_DagSize(res);
+ if (sizeF <= sizeRes) {
+ Cudd_IterDerefBdd(dd, res);
+ return(f);
+ } else {
+ cuddDeref(res);
+ return(res);
+ }
+
+} /* end of Cudd_bddRestrict */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes f constrain c for ADDs.]
+
+ Description [Computes f constrain c (f @ c), for f an ADD and c a 0-1
+ ADD. List of special cases:
+ <ul>
+ <li> F @ 0 = 0
+ <li> F @ 1 = F
+ <li> 0 @ c = 0
+ <li> 1 @ c = 1
+ <li> F @ F = 1
+ </ul>
+ Returns a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddConstrain]
+
+******************************************************************************/
+DdNode *
+Cudd_addConstrain(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * c)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddAddConstrainRecur(dd,f,c);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_addConstrain */
+
+
+/**Function********************************************************************
+
+ Synopsis [BDD conjunctive decomposition as in McMillan's CAV96 paper.]
+
+ Description [BDD conjunctive decomposition as in McMillan's CAV96
+ paper. The decomposition is canonical only for a given variable
+ order. If canonicity is required, variable ordering must be disabled
+ after the decomposition has been computed. Returns an array with one
+ entry for each BDD variable in the manager if successful; otherwise
+ NULL. The components of the solution have their reference counts
+ already incremented (unlike the results of most other functions in
+ the package.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddConstrain Cudd_bddExistAbstract]
+
+******************************************************************************/
+DdNode **
+Cudd_bddConstrainDecomp(
+ DdManager * dd,
+ DdNode * f)
+{
+ DdNode **decomp;
+ int res;
+ int i;
+
+ /* Create an initialize decomposition array. */
+ decomp = ALLOC(DdNode *,dd->size);
+ if (decomp == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < dd->size; i++) {
+ decomp[i] = NULL;
+ }
+ do {
+ dd->reordered = 0;
+ /* Clean up the decomposition array in case reordering took place. */
+ for (i = 0; i < dd->size; i++) {
+ if (decomp[i] != NULL) {
+ Cudd_IterDerefBdd(dd, decomp[i]);
+ decomp[i] = NULL;
+ }
+ }
+ res = cuddBddConstrainDecomp(dd,f,decomp);
+ } while (dd->reordered == 1);
+ if (res == 0) {
+ FREE(decomp);
+ return(NULL);
+ }
+ /* Missing components are constant ones. */
+ for (i = 0; i < dd->size; i++) {
+ if (decomp[i] == NULL) {
+ decomp[i] = DD_ONE(dd);
+ cuddRef(decomp[i]);
+ }
+ }
+ return(decomp);
+
+} /* end of Cudd_bddConstrainDecomp */
+
+
+/**Function********************************************************************
+
+ Synopsis [ADD restrict according to Coudert and Madre's algorithm
+ (ICCAD90).]
+
+ Description [ADD restrict according to Coudert and Madre's algorithm
+ (ICCAD90). Returns the restricted ADD if successful; otherwise NULL.
+ If application of restrict results in an ADD larger than the input
+ ADD, the input ADD is returned.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addConstrain Cudd_bddRestrict]
+
+******************************************************************************/
+DdNode *
+Cudd_addRestrict(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * c)
+{
+ DdNode *supp_f, *supp_c;
+ DdNode *res, *commonSupport;
+ int intersection;
+ int sizeF, sizeRes;
+
+ /* Check if supports intersect. */
+ supp_f = Cudd_Support(dd, f);
+ if (supp_f == NULL) {
+ return(NULL);
+ }
+ cuddRef(supp_f);
+ supp_c = Cudd_Support(dd, c);
+ if (supp_c == NULL) {
+ Cudd_RecursiveDeref(dd,supp_f);
+ return(NULL);
+ }
+ cuddRef(supp_c);
+ commonSupport = Cudd_bddLiteralSetIntersection(dd, supp_f, supp_c);
+ if (commonSupport == NULL) {
+ Cudd_RecursiveDeref(dd,supp_f);
+ Cudd_RecursiveDeref(dd,supp_c);
+ return(NULL);
+ }
+ cuddRef(commonSupport);
+ Cudd_RecursiveDeref(dd,supp_f);
+ Cudd_RecursiveDeref(dd,supp_c);
+ intersection = commonSupport != DD_ONE(dd);
+ Cudd_RecursiveDeref(dd,commonSupport);
+
+ if (intersection) {
+ do {
+ dd->reordered = 0;
+ res = cuddAddRestrictRecur(dd, f, c);
+ } while (dd->reordered == 1);
+ sizeF = Cudd_DagSize(f);
+ sizeRes = Cudd_DagSize(res);
+ if (sizeF <= sizeRes) {
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd, res);
+ return(f);
+ } else {
+ return(res);
+ }
+ } else {
+ return(f);
+ }
+
+} /* end of Cudd_addRestrict */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes a vector whose image equals a non-zero function.]
+
+ Description [Computes a vector of BDDs whose image equals a non-zero
+ function.
+ The result depends on the variable order. The i-th component of the vector
+ depends only on the first i variables in the order. Each BDD in the vector
+ is not larger than the BDD of the given characteristic function. This
+ function is based on the description of char-to-vect in "Verification of
+ Sequential Machines Using Boolean Functional Vectors" by O. Coudert, C.
+ Berthet and J. C. Madre.
+ Returns a pointer to an array containing the result if successful; NULL
+ otherwise. The size of the array equals the number of variables in the
+ manager. The components of the solution have their reference counts
+ already incremented (unlike the results of most other functions in
+ the package.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddConstrain]
+
+******************************************************************************/
+DdNode **
+Cudd_bddCharToVect(
+ DdManager * dd,
+ DdNode * f)
+{
+ int i, j;
+ DdNode **vect;
+ DdNode *res = NULL;
+
+ if (f == Cudd_Not(DD_ONE(dd))) return(NULL);
+
+ vect = ALLOC(DdNode *, dd->size);
+ if (vect == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+
+ do {
+ dd->reordered = 0;
+ for (i = 0; i < dd->size; i++) {
+ res = cuddBddCharToVect(dd,f,dd->vars[dd->invperm[i]]);
+ if (res == NULL) {
+ /* Clean up the vector array in case reordering took place. */
+ for (j = 0; j < i; j++) {
+ Cudd_IterDerefBdd(dd, vect[dd->invperm[j]]);
+ }
+ break;
+ }
+ cuddRef(res);
+ vect[dd->invperm[i]] = res;
+ }
+ } while (dd->reordered == 1);
+ if (res == NULL) {
+ FREE(vect);
+ return(NULL);
+ }
+ return(vect);
+
+} /* end of Cudd_bddCharToVect */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs safe minimization of a BDD.]
+
+ Description [Performs safe minimization of a BDD. Given the BDD
+ <code>f</code> of a function to be minimized and a BDD
+ <code>c</code> representing the care set, Cudd_bddLICompaction
+ produces the BDD of a function that agrees with <code>f</code>
+ wherever <code>c</code> is 1. Safe minimization means that the size
+ of the result is guaranteed not to exceed the size of
+ <code>f</code>. This function is based on the DAC97 paper by Hong et
+ al.. Returns a pointer to the result if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddRestrict]
+
+******************************************************************************/
+DdNode *
+Cudd_bddLICompaction(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be minimized */,
+ DdNode * c /* constraint (care set) */)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddLICompaction(dd,f,c);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddLICompaction */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds a small BDD in a function interval.]
+
+ Description [Finds a small BDD in a function interval. Given BDDs
+ <code>l</code> and <code>u</code>, representing the lower bound and
+ upper bound of a function interval, Cudd_bddSqueeze produces the BDD
+ of a function within the interval with a small BDD. Returns a
+ pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddRestrict Cudd_bddLICompaction]
+
+******************************************************************************/
+DdNode *
+Cudd_bddSqueeze(
+ DdManager * dd /* manager */,
+ DdNode * l /* lower bound */,
+ DdNode * u /* upper bound */)
+{
+ DdNode *res;
+ int sizeRes, sizeL, sizeU;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddSqueeze(dd,l,u);
+ } while (dd->reordered == 1);
+ if (res == NULL) return(NULL);
+ /* We now compare the result with the bounds and return the smallest.
+ ** We first compare to u, so that in case l == 0 and u == 1, we return
+ ** 0 as in other minimization algorithms. */
+ sizeRes = Cudd_DagSize(res);
+ sizeU = Cudd_DagSize(u);
+ if (sizeU <= sizeRes) {
+ cuddRef(res);
+ Cudd_IterDerefBdd(dd,res);
+ res = u;
+ sizeRes = sizeU;
+ }
+ sizeL = Cudd_DagSize(l);
+ if (sizeL <= sizeRes) {
+ cuddRef(res);
+ Cudd_IterDerefBdd(dd,res);
+ res = l;
+ sizeRes = sizeL;
+ }
+ return(res);
+
+} /* end of Cudd_bddSqueeze */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds a small BDD that agrees with <code>f</code> over
+ <code>c</code>.]
+
+ Description [Finds a small BDD that agrees with <code>f</code> over
+ <code>c</code>. Returns a pointer to the result if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddRestrict Cudd_bddLICompaction Cudd_bddSqueeze]
+
+******************************************************************************/
+DdNode *
+Cudd_bddMinimize(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * c)
+{
+ DdNode *cplus, *res;
+
+ if (c == Cudd_Not(DD_ONE(dd))) return(c);
+ if (Cudd_IsConstant(f)) return(f);
+ if (f == c) return(DD_ONE(dd));
+ if (f == Cudd_Not(c)) return(Cudd_Not(DD_ONE(dd)));
+
+ cplus = Cudd_RemapOverApprox(dd,c,0,0,1.0);
+ if (cplus == NULL) return(NULL);
+ cuddRef(cplus);
+ res = Cudd_bddLICompaction(dd,f,cplus);
+ if (res == NULL) {
+ Cudd_IterDerefBdd(dd,cplus);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_IterDerefBdd(dd,cplus);
+ cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_bddMinimize */
+
+
+/**Function********************************************************************
+
+ Synopsis [Find a dense subset of BDD <code>f</code>.]
+
+ Description [Finds a dense subset of BDD <code>f</code>. Density is
+ the ratio of number of minterms to number of nodes. Uses several
+ techniques in series. It is more expensive than other subsetting
+ procedures, but often produces better results. See
+ Cudd_SubsetShortPaths for a description of the threshold and nvars
+ parameters. Returns a pointer to the result if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SubsetRemap Cudd_SubsetShortPaths Cudd_SubsetHeavyBranch
+ Cudd_bddSqueeze]
+
+******************************************************************************/
+DdNode *
+Cudd_SubsetCompress(
+ DdManager * dd /* manager */,
+ DdNode * f /* BDD whose subset is sought */,
+ int nvars /* number of variables in the support of f */,
+ int threshold /* maximum number of nodes in the subset */)
+{
+ DdNode *res, *tmp1, *tmp2;
+
+ tmp1 = Cudd_SubsetShortPaths(dd, f, nvars, threshold, 0);
+ if (tmp1 == NULL) return(NULL);
+ cuddRef(tmp1);
+ tmp2 = Cudd_RemapUnderApprox(dd,tmp1,nvars,0,1.0);
+ if (tmp2 == NULL) {
+ Cudd_IterDerefBdd(dd,tmp1);
+ return(NULL);
+ }
+ cuddRef(tmp2);
+ Cudd_IterDerefBdd(dd,tmp1);
+ res = Cudd_bddSqueeze(dd,tmp2,f);
+ if (res == NULL) {
+ Cudd_IterDerefBdd(dd,tmp2);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_IterDerefBdd(dd,tmp2);
+ cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_SubsetCompress */
+
+
+/**Function********************************************************************
+
+ Synopsis [Find a dense superset of BDD <code>f</code>.]
+
+ Description [Finds a dense superset of BDD <code>f</code>. Density is
+ the ratio of number of minterms to number of nodes. Uses several
+ techniques in series. It is more expensive than other supersetting
+ procedures, but often produces better results. See
+ Cudd_SupersetShortPaths for a description of the threshold and nvars
+ parameters. Returns a pointer to the result if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SubsetCompress Cudd_SupersetRemap Cudd_SupersetShortPaths
+ Cudd_SupersetHeavyBranch Cudd_bddSqueeze]
+
+******************************************************************************/
+DdNode *
+Cudd_SupersetCompress(
+ DdManager * dd /* manager */,
+ DdNode * f /* BDD whose superset is sought */,
+ int nvars /* number of variables in the support of f */,
+ int threshold /* maximum number of nodes in the superset */)
+{
+ DdNode *subset;
+
+ subset = Cudd_SubsetCompress(dd, Cudd_Not(f),nvars,threshold);
+
+ return(Cudd_NotCond(subset, (subset != NULL)));
+
+} /* end of Cudd_SupersetCompress */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddConstrain.]
+
+ Description [Performs the recursive step of Cudd_bddConstrain.
+ Returns a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddConstrain]
+
+******************************************************************************/
+DdNode *
+cuddBddConstrainRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * c)
+{
+ DdNode *Fv, *Fnv, *Cv, *Cnv, *t, *e, *r;
+ DdNode *one, *zero;
+ unsigned int topf, topc;
+ int index;
+ int comple = 0;
+
+ statLine(dd);
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+
+ /* Trivial cases. */
+ if (c == one) return(f);
+ if (c == zero) return(zero);
+ if (Cudd_IsConstant(f)) return(f);
+ if (f == c) return(one);
+ if (f == Cudd_Not(c)) return(zero);
+
+ /* Make canonical to increase the utilization of the cache. */
+ if (Cudd_IsComplement(f)) {
+ f = Cudd_Not(f);
+ comple = 1;
+ }
+ /* Now f is a regular pointer to a non-constant node; c is also
+ ** non-constant, but may be complemented.
+ */
+
+ /* Check the cache. */
+ r = cuddCacheLookup2(dd, Cudd_bddConstrain, f, c);
+ if (r != NULL) {
+ return(Cudd_NotCond(r,comple));
+ }
+
+ /* Recursive step. */
+ topf = dd->perm[f->index];
+ topc = dd->perm[Cudd_Regular(c)->index];
+ if (topf <= topc) {
+ index = f->index;
+ Fv = cuddT(f); Fnv = cuddE(f);
+ } else {
+ index = Cudd_Regular(c)->index;
+ Fv = Fnv = f;
+ }
+ if (topc <= topf) {
+ Cv = cuddT(Cudd_Regular(c)); Cnv = cuddE(Cudd_Regular(c));
+ if (Cudd_IsComplement(c)) {
+ Cv = Cudd_Not(Cv);
+ Cnv = Cudd_Not(Cnv);
+ }
+ } else {
+ Cv = Cnv = c;
+ }
+
+ if (!Cudd_IsConstant(Cv)) {
+ t = cuddBddConstrainRecur(dd, Fv, Cv);
+ if (t == NULL)
+ return(NULL);
+ } else if (Cv == one) {
+ t = Fv;
+ } else { /* Cv == zero: return Fnv @ Cnv */
+ if (Cnv == one) {
+ r = Fnv;
+ } else {
+ r = cuddBddConstrainRecur(dd, Fnv, Cnv);
+ if (r == NULL)
+ return(NULL);
+ }
+ return(Cudd_NotCond(r,comple));
+ }
+ cuddRef(t);
+
+ if (!Cudd_IsConstant(Cnv)) {
+ e = cuddBddConstrainRecur(dd, Fnv, Cnv);
+ if (e == NULL) {
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ } else if (Cnv == one) {
+ e = Fnv;
+ } else { /* Cnv == zero: return Fv @ Cv previously computed */
+ cuddDeref(t);
+ return(Cudd_NotCond(t,comple));
+ }
+ cuddRef(e);
+
+ if (Cudd_IsComplement(t)) {
+ t = Cudd_Not(t);
+ e = Cudd_Not(e);
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, e);
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, e);
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+
+ cuddCacheInsert2(dd, Cudd_bddConstrain, f, c, r);
+ return(Cudd_NotCond(r,comple));
+
+} /* end of cuddBddConstrainRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddRestrict.]
+
+ Description [Performs the recursive step of Cudd_bddRestrict.
+ Returns the restricted BDD if successful; otherwise NULL.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddRestrict]
+
+******************************************************************************/
+DdNode *
+cuddBddRestrictRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * c)
+{
+ DdNode *Fv, *Fnv, *Cv, *Cnv, *t, *e, *r, *one, *zero;
+ unsigned int topf, topc;
+ int index;
+ int comple = 0;
+
+ statLine(dd);
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+
+ /* Trivial cases */
+ if (c == one) return(f);
+ if (c == zero) return(zero);
+ if (Cudd_IsConstant(f)) return(f);
+ if (f == c) return(one);
+ if (f == Cudd_Not(c)) return(zero);
+
+ /* Make canonical to increase the utilization of the cache. */
+ if (Cudd_IsComplement(f)) {
+ f = Cudd_Not(f);
+ comple = 1;
+ }
+ /* Now f is a regular pointer to a non-constant node; c is also
+ ** non-constant, but may be complemented.
+ */
+
+ /* Check the cache. */
+ r = cuddCacheLookup2(dd, Cudd_bddRestrict, f, c);
+ if (r != NULL) {
+ return(Cudd_NotCond(r,comple));
+ }
+
+ topf = dd->perm[f->index];
+ topc = dd->perm[Cudd_Regular(c)->index];
+
+ if (topc < topf) { /* abstract top variable from c */
+ DdNode *d, *s1, *s2;
+
+ /* Find complements of cofactors of c. */
+ if (Cudd_IsComplement(c)) {
+ s1 = cuddT(Cudd_Regular(c));
+ s2 = cuddE(Cudd_Regular(c));
+ } else {
+ s1 = Cudd_Not(cuddT(c));
+ s2 = Cudd_Not(cuddE(c));
+ }
+ /* Take the OR by applying DeMorgan. */
+ d = cuddBddAndRecur(dd, s1, s2);
+ if (d == NULL) return(NULL);
+ d = Cudd_Not(d);
+ cuddRef(d);
+ r = cuddBddRestrictRecur(dd, f, d);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, d);
+ return(NULL);
+ }
+ cuddRef(r);
+ Cudd_IterDerefBdd(dd, d);
+ cuddCacheInsert2(dd, Cudd_bddRestrict, f, c, r);
+ cuddDeref(r);
+ return(Cudd_NotCond(r,comple));
+ }
+
+ /* Recursive step. Here topf <= topc. */
+ index = f->index;
+ Fv = cuddT(f); Fnv = cuddE(f);
+ if (topc == topf) {
+ Cv = cuddT(Cudd_Regular(c)); Cnv = cuddE(Cudd_Regular(c));
+ if (Cudd_IsComplement(c)) {
+ Cv = Cudd_Not(Cv);
+ Cnv = Cudd_Not(Cnv);
+ }
+ } else {
+ Cv = Cnv = c;
+ }
+
+ if (!Cudd_IsConstant(Cv)) {
+ t = cuddBddRestrictRecur(dd, Fv, Cv);
+ if (t == NULL) return(NULL);
+ } else if (Cv == one) {
+ t = Fv;
+ } else { /* Cv == zero: return(Fnv @ Cnv) */
+ if (Cnv == one) {
+ r = Fnv;
+ } else {
+ r = cuddBddRestrictRecur(dd, Fnv, Cnv);
+ if (r == NULL) return(NULL);
+ }
+ return(Cudd_NotCond(r,comple));
+ }
+ cuddRef(t);
+
+ if (!Cudd_IsConstant(Cnv)) {
+ e = cuddBddRestrictRecur(dd, Fnv, Cnv);
+ if (e == NULL) {
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ } else if (Cnv == one) {
+ e = Fnv;
+ } else { /* Cnv == zero: return (Fv @ Cv) previously computed */
+ cuddDeref(t);
+ return(Cudd_NotCond(t,comple));
+ }
+ cuddRef(e);
+
+ if (Cudd_IsComplement(t)) {
+ t = Cudd_Not(t);
+ e = Cudd_Not(e);
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, e);
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, e);
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+
+ cuddCacheInsert2(dd, Cudd_bddRestrict, f, c, r);
+ return(Cudd_NotCond(r,comple));
+
+} /* end of cuddBddRestrictRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addConstrain.]
+
+ Description [Performs the recursive step of Cudd_addConstrain.
+ Returns a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addConstrain]
+
+******************************************************************************/
+DdNode *
+cuddAddConstrainRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * c)
+{
+ DdNode *Fv, *Fnv, *Cv, *Cnv, *t, *e, *r;
+ DdNode *one, *zero;
+ unsigned int topf, topc;
+ int index;
+
+ statLine(dd);
+ one = DD_ONE(dd);
+ zero = DD_ZERO(dd);
+
+ /* Trivial cases. */
+ if (c == one) return(f);
+ if (c == zero) return(zero);
+ if (Cudd_IsConstant(f)) return(f);
+ if (f == c) return(one);
+
+ /* Now f and c are non-constant. */
+
+ /* Check the cache. */
+ r = cuddCacheLookup2(dd, Cudd_addConstrain, f, c);
+ if (r != NULL) {
+ return(r);
+ }
+
+ /* Recursive step. */
+ topf = dd->perm[f->index];
+ topc = dd->perm[c->index];
+ if (topf <= topc) {
+ index = f->index;
+ Fv = cuddT(f); Fnv = cuddE(f);
+ } else {
+ index = c->index;
+ Fv = Fnv = f;
+ }
+ if (topc <= topf) {
+ Cv = cuddT(c); Cnv = cuddE(c);
+ } else {
+ Cv = Cnv = c;
+ }
+
+ if (!Cudd_IsConstant(Cv)) {
+ t = cuddAddConstrainRecur(dd, Fv, Cv);
+ if (t == NULL)
+ return(NULL);
+ } else if (Cv == one) {
+ t = Fv;
+ } else { /* Cv == zero: return Fnv @ Cnv */
+ if (Cnv == one) {
+ r = Fnv;
+ } else {
+ r = cuddAddConstrainRecur(dd, Fnv, Cnv);
+ if (r == NULL)
+ return(NULL);
+ }
+ return(r);
+ }
+ cuddRef(t);
+
+ if (!Cudd_IsConstant(Cnv)) {
+ e = cuddAddConstrainRecur(dd, Fnv, Cnv);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ } else if (Cnv == one) {
+ e = Fnv;
+ } else { /* Cnv == zero: return Fv @ Cv previously computed */
+ cuddDeref(t);
+ return(t);
+ }
+ cuddRef(e);
+
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd, e);
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+
+ cuddCacheInsert2(dd, Cudd_addConstrain, f, c, r);
+ return(r);
+
+} /* end of cuddAddConstrainRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addRestrict.]
+
+ Description [Performs the recursive step of Cudd_addRestrict.
+ Returns the restricted ADD if successful; otherwise NULL.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addRestrict]
+
+******************************************************************************/
+DdNode *
+cuddAddRestrictRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * c)
+{
+ DdNode *Fv, *Fnv, *Cv, *Cnv, *t, *e, *r, *one, *zero;
+ unsigned int topf, topc;
+ int index;
+
+ statLine(dd);
+ one = DD_ONE(dd);
+ zero = DD_ZERO(dd);
+
+ /* Trivial cases */
+ if (c == one) return(f);
+ if (c == zero) return(zero);
+ if (Cudd_IsConstant(f)) return(f);
+ if (f == c) return(one);
+
+ /* Now f and c are non-constant. */
+
+ /* Check the cache. */
+ r = cuddCacheLookup2(dd, Cudd_addRestrict, f, c);
+ if (r != NULL) {
+ return(r);
+ }
+
+ topf = dd->perm[f->index];
+ topc = dd->perm[c->index];
+
+ if (topc < topf) { /* abstract top variable from c */
+ DdNode *d, *s1, *s2;
+
+ /* Find cofactors of c. */
+ s1 = cuddT(c);
+ s2 = cuddE(c);
+ /* Take the OR by applying DeMorgan. */
+ d = cuddAddApplyRecur(dd, Cudd_addOr, s1, s2);
+ if (d == NULL) return(NULL);
+ cuddRef(d);
+ r = cuddAddRestrictRecur(dd, f, d);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd, d);
+ return(NULL);
+ }
+ cuddRef(r);
+ Cudd_RecursiveDeref(dd, d);
+ cuddCacheInsert2(dd, Cudd_addRestrict, f, c, r);
+ cuddDeref(r);
+ return(r);
+ }
+
+ /* Recursive step. Here topf <= topc. */
+ index = f->index;
+ Fv = cuddT(f); Fnv = cuddE(f);
+ if (topc == topf) {
+ Cv = cuddT(c); Cnv = cuddE(c);
+ } else {
+ Cv = Cnv = c;
+ }
+
+ if (!Cudd_IsConstant(Cv)) {
+ t = cuddAddRestrictRecur(dd, Fv, Cv);
+ if (t == NULL) return(NULL);
+ } else if (Cv == one) {
+ t = Fv;
+ } else { /* Cv == zero: return(Fnv @ Cnv) */
+ if (Cnv == one) {
+ r = Fnv;
+ } else {
+ r = cuddAddRestrictRecur(dd, Fnv, Cnv);
+ if (r == NULL) return(NULL);
+ }
+ return(r);
+ }
+ cuddRef(t);
+
+ if (!Cudd_IsConstant(Cnv)) {
+ e = cuddAddRestrictRecur(dd, Fnv, Cnv);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ } else if (Cnv == one) {
+ e = Fnv;
+ } else { /* Cnv == zero: return (Fv @ Cv) previously computed */
+ cuddDeref(t);
+ return(t);
+ }
+ cuddRef(e);
+
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd, e);
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+
+ cuddCacheInsert2(dd, Cudd_addRestrict, f, c, r);
+ return(r);
+
+} /* end of cuddAddRestrictRecur */
+
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs safe minimization of a BDD.]
+
+ Description [Performs safe minimization of a BDD. Given the BDD
+ <code>f</code> of a function to be minimized and a BDD
+ <code>c</code> representing the care set, Cudd_bddLICompaction
+ produces the BDD of a function that agrees with <code>f</code>
+ wherever <code>c</code> is 1. Safe minimization means that the size
+ of the result is guaranteed not to exceed the size of
+ <code>f</code>. This function is based on the DAC97 paper by Hong et
+ al.. Returns a pointer to the result if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddLICompaction]
+
+******************************************************************************/
+DdNode *
+cuddBddLICompaction(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be minimized */,
+ DdNode * c /* constraint (care set) */)
+{
+ st_table *marktable, *markcache, *buildcache;
+ DdNode *res, *zero;
+
+ zero = Cudd_Not(DD_ONE(dd));
+ if (c == zero) return(zero);
+
+ /* We need to use local caches for both steps of this operation.
+ ** The results of the edge marking step are only valid as long as the
+ ** edge markings themselves are available. However, the edge markings
+ ** are lost at the end of one invocation of Cudd_bddLICompaction.
+ ** Hence, the cache entries for the edge marking step must be
+ ** invalidated at the end of this function.
+ ** For the result of the building step we argue as follows. The result
+ ** for a node and a given constrain depends on the BDD in which the node
+ ** appears. Hence, the same node and constrain may give different results
+ ** in successive invocations.
+ */
+ marktable = st_init_table(st_ptrcmp,st_ptrhash);
+ if (marktable == NULL) {
+ return(NULL);
+ }
+ markcache = st_init_table(MarkCacheCompare,MarkCacheHash);
+ if (markcache == NULL) {
+ st_free_table(marktable);
+ return(NULL);
+ }
+ if (cuddBddLICMarkEdges(dd,f,c,marktable,markcache) == CUDD_OUT_OF_MEM) {
+ st_foreach(markcache, MarkCacheCleanUp, NULL);
+ st_free_table(marktable);
+ st_free_table(markcache);
+ return(NULL);
+ }
+ st_foreach(markcache, MarkCacheCleanUp, NULL);
+ st_free_table(markcache);
+ buildcache = st_init_table(st_ptrcmp,st_ptrhash);
+ if (buildcache == NULL) {
+ st_free_table(marktable);
+ return(NULL);
+ }
+ res = cuddBddLICBuildResult(dd,f,buildcache,marktable);
+ st_free_table(buildcache);
+ st_free_table(marktable);
+ return(res);
+
+} /* end of cuddBddLICompaction */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddConstrainDecomp.]
+
+ Description [Performs the recursive step of Cudd_bddConstrainDecomp.
+ Returns f super (i) if successful; otherwise NULL.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddConstrainDecomp]
+
+******************************************************************************/
+static int
+cuddBddConstrainDecomp(
+ DdManager * dd,
+ DdNode * f,
+ DdNode ** decomp)
+{
+ DdNode *F, *fv, *fvn;
+ DdNode *fAbs;
+ DdNode *result;
+ int ok;
+
+ if (Cudd_IsConstant(f)) return(1);
+ /* Compute complements of cofactors. */
+ F = Cudd_Regular(f);
+ fv = cuddT(F);
+ fvn = cuddE(F);
+ if (F == f) {
+ fv = Cudd_Not(fv);
+ fvn = Cudd_Not(fvn);
+ }
+ /* Compute abstraction of top variable. */
+ fAbs = cuddBddAndRecur(dd, fv, fvn);
+ if (fAbs == NULL) {
+ return(0);
+ }
+ cuddRef(fAbs);
+ fAbs = Cudd_Not(fAbs);
+ /* Recursively find the next abstraction and the components of the
+ ** decomposition. */
+ ok = cuddBddConstrainDecomp(dd, fAbs, decomp);
+ if (ok == 0) {
+ Cudd_IterDerefBdd(dd,fAbs);
+ return(0);
+ }
+ /* Compute the component of the decomposition corresponding to the
+ ** top variable and store it in the decomposition array. */
+ result = cuddBddConstrainRecur(dd, f, fAbs);
+ if (result == NULL) {
+ Cudd_IterDerefBdd(dd,fAbs);
+ return(0);
+ }
+ cuddRef(result);
+ decomp[F->index] = result;
+ Cudd_IterDerefBdd(dd, fAbs);
+ return(1);
+
+} /* end of cuddBddConstrainDecomp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddCharToVect.]
+
+ Description [Performs the recursive step of Cudd_bddCharToVect.
+ This function maintains the invariant that f is non-zero.
+ Returns the i-th component of the vector if successful; otherwise NULL.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddCharToVect]
+
+******************************************************************************/
+static DdNode *
+cuddBddCharToVect(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * x)
+{
+ unsigned int topf;
+ unsigned int level;
+ int comple;
+
+ DdNode *one, *zero, *res, *F, *fT, *fE, *T, *E;
+
+ statLine(dd);
+ /* Check the cache. */
+ res = cuddCacheLookup2(dd, cuddBddCharToVect, f, x);
+ if (res != NULL) {
+ return(res);
+ }
+
+ F = Cudd_Regular(f);
+
+ topf = cuddI(dd,F->index);
+ level = dd->perm[x->index];
+
+ if (topf > level) return(x);
+
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+
+ comple = F != f;
+ fT = Cudd_NotCond(cuddT(F),comple);
+ fE = Cudd_NotCond(cuddE(F),comple);
+
+ if (topf == level) {
+ if (fT == zero) return(zero);
+ if (fE == zero) return(one);
+ return(x);
+ }
+
+ /* Here topf < level. */
+ if (fT == zero) return(cuddBddCharToVect(dd, fE, x));
+ if (fE == zero) return(cuddBddCharToVect(dd, fT, x));
+
+ T = cuddBddCharToVect(dd, fT, x);
+ if (T == NULL) {
+ return(NULL);
+ }
+ cuddRef(T);
+ E = cuddBddCharToVect(dd, fE, x);
+ if (E == NULL) {
+ Cudd_IterDerefBdd(dd,T);
+ return(NULL);
+ }
+ cuddRef(E);
+ res = cuddBddIteRecur(dd, dd->vars[F->index], T, E);
+ if (res == NULL) {
+ Cudd_IterDerefBdd(dd,T);
+ Cudd_IterDerefBdd(dd,E);
+ return(NULL);
+ }
+ cuddDeref(T);
+ cuddDeref(E);
+ cuddCacheInsert2(dd, cuddBddCharToVect, f, x, res);
+ return(res);
+
+} /* end of cuddBddCharToVect */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the edge marking step of Cudd_bddLICompaction.]
+
+ Description [Performs the edge marking step of Cudd_bddLICompaction.
+ Returns the LUB of the markings of the two outgoing edges of <code>f</code>
+ if successful; otherwise CUDD_OUT_OF_MEM.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddLICompaction cuddBddLICBuildResult]
+
+******************************************************************************/
+static int
+cuddBddLICMarkEdges(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * c,
+ st_table * table,
+ st_table * cache)
+{
+ DdNode *Fv, *Fnv, *Cv, *Cnv;
+ DdNode *one, *zero;
+ unsigned int topf, topc;
+ int index;
+ int comple;
+ int resT, resE, res, retval;
+ char **slot;
+ MarkCacheKey *key;
+
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+
+ /* Terminal cases. */
+ if (c == zero) return(DD_LIC_DC);
+ if (f == one) return(DD_LIC_1);
+ if (f == zero) return(DD_LIC_0);
+
+ /* Make canonical to increase the utilization of the cache. */
+ comple = Cudd_IsComplement(f);
+ f = Cudd_Regular(f);
+ /* Now f is a regular pointer to a non-constant node; c may be
+ ** constant, or it may be complemented.
+ */
+
+ /* Check the cache. */
+ key = ALLOC(MarkCacheKey, 1);
+ if (key == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(CUDD_OUT_OF_MEM);
+ }
+ key->f = f; key->c = c;
+ if (st_lookup(cache, (char *)key, (char **)&res)) {
+ FREE(key);
+ if (comple) {
+ if (res == DD_LIC_0) res = DD_LIC_1;
+ else if (res == DD_LIC_1) res = DD_LIC_0;
+ }
+ return(res);
+ }
+
+ /* Recursive step. */
+ topf = dd->perm[f->index];
+ topc = cuddI(dd,Cudd_Regular(c)->index);
+ if (topf <= topc) {
+ index = f->index;
+ Fv = cuddT(f); Fnv = cuddE(f);
+ } else {
+ index = Cudd_Regular(c)->index;
+ Fv = Fnv = f;
+ }
+ if (topc <= topf) {
+ /* We know that c is not constant because f is not. */
+ Cv = cuddT(Cudd_Regular(c)); Cnv = cuddE(Cudd_Regular(c));
+ if (Cudd_IsComplement(c)) {
+ Cv = Cudd_Not(Cv);
+ Cnv = Cudd_Not(Cnv);
+ }
+ } else {
+ Cv = Cnv = c;
+ }
+
+ resT = cuddBddLICMarkEdges(dd, Fv, Cv, table, cache);
+ if (resT == CUDD_OUT_OF_MEM) {
+ FREE(key);
+ return(CUDD_OUT_OF_MEM);
+ }
+ resE = cuddBddLICMarkEdges(dd, Fnv, Cnv, table, cache);
+ if (resE == CUDD_OUT_OF_MEM) {
+ FREE(key);
+ return(CUDD_OUT_OF_MEM);
+ }
+
+ /* Update edge markings. */
+ if (topf <= topc) {
+ retval = st_find_or_add(table, (char *)f, (char ***)&slot);
+ if (retval == 0) {
+ *slot = (char *) (ptrint)((resT << 2) | resE);
+ } else if (retval == 1) {
+ *slot = (char *) (ptrint)((int)((ptrint) *slot) | (resT << 2) | resE);
+ } else {
+ FREE(key);
+ return(CUDD_OUT_OF_MEM);
+ }
+ }
+
+ /* Cache result. */
+ res = resT | resE;
+ if (st_insert(cache, (char *)key, (char *)(ptrint)res) == ST_OUT_OF_MEM) {
+ FREE(key);
+ return(CUDD_OUT_OF_MEM);
+ }
+
+ /* Take into account possible complementation. */
+ if (comple) {
+ if (res == DD_LIC_0) res = DD_LIC_1;
+ else if (res == DD_LIC_1) res = DD_LIC_0;
+ }
+ return(res);
+
+} /* end of cuddBddLICMarkEdges */
+
+
+/**Function********************************************************************
+
+ Synopsis [Builds the result of Cudd_bddLICompaction.]
+
+ Description [Builds the results of Cudd_bddLICompaction.
+ Returns a pointer to the minimized BDD if successful; otherwise NULL.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddLICompaction cuddBddLICMarkEdges]
+
+******************************************************************************/
+static DdNode *
+cuddBddLICBuildResult(
+ DdManager * dd,
+ DdNode * f,
+ st_table * cache,
+ st_table * table)
+{
+ DdNode *Fv, *Fnv, *r, *t, *e;
+ DdNode *one, *zero;
+ unsigned int topf;
+ int index;
+ int comple;
+ int markT, markE, markings;
+
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+
+ if (Cudd_IsConstant(f)) return(f);
+ /* Make canonical to increase the utilization of the cache. */
+ comple = Cudd_IsComplement(f);
+ f = Cudd_Regular(f);
+
+ /* Check the cache. */
+ if (st_lookup(cache, (char *)f, (char **)&r)) {
+ return(Cudd_NotCond(r,comple));
+ }
+
+ /* Retrieve the edge markings. */
+ if (st_lookup(table, (char *)f, (char **)&markings) == 0)
+ return(NULL);
+ markT = markings >> 2;
+ markE = markings & 3;
+
+ topf = dd->perm[f->index];
+ index = f->index;
+ Fv = cuddT(f); Fnv = cuddE(f);
+
+ if (markT == DD_LIC_NL) {
+ t = cuddBddLICBuildResult(dd,Fv,cache,table);
+ if (t == NULL) {
+ return(NULL);
+ }
+ } else if (markT == DD_LIC_1) {
+ t = one;
+ } else {
+ t = zero;
+ }
+ cuddRef(t);
+ if (markE == DD_LIC_NL) {
+ e = cuddBddLICBuildResult(dd,Fnv,cache,table);
+ if (e == NULL) {
+ Cudd_IterDerefBdd(dd,t);
+ return(NULL);
+ }
+ } else if (markE == DD_LIC_1) {
+ e = one;
+ } else {
+ e = zero;
+ }
+ cuddRef(e);
+
+ if (markT == DD_LIC_DC && markE != DD_LIC_DC) {
+ r = e;
+ } else if (markT != DD_LIC_DC && markE == DD_LIC_DC) {
+ r = t;
+ } else {
+ if (Cudd_IsComplement(t)) {
+ t = Cudd_Not(t);
+ e = Cudd_Not(e);
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, e);
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, e);
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ }
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+
+ if (st_insert(cache, (char *)f, (char *)r) == ST_OUT_OF_MEM) {
+ cuddRef(r);
+ Cudd_IterDerefBdd(dd,r);
+ return(NULL);
+ }
+
+ return(Cudd_NotCond(r,comple));
+
+} /* end of cuddBddLICBuildResult */
+
+
+/**Function********************************************************************
+
+ Synopsis [Hash function for the computed table of cuddBddLICMarkEdges.]
+
+ Description [Hash function for the computed table of
+ cuddBddLICMarkEdges. Returns the bucket number.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddLICompaction]
+
+******************************************************************************/
+static int
+MarkCacheHash(
+ char * ptr,
+ int modulus)
+{
+ int val = 0;
+ MarkCacheKey *entry;
+
+ entry = (MarkCacheKey *) ptr;
+
+ val = (int) (ptrint) entry->f;
+ val = val * 997 + (int) (ptrint) entry->c;
+
+ return ((val < 0) ? -val : val) % modulus;
+
+} /* end of MarkCacheHash */
+
+
+/**Function********************************************************************
+
+ Synopsis [Comparison function for the computed table of
+ cuddBddLICMarkEdges.]
+
+ Description [Comparison function for the computed table of
+ cuddBddLICMarkEdges. Returns 0 if the two nodes of the key are equal; 1
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddLICompaction]
+
+******************************************************************************/
+static int
+MarkCacheCompare(
+ const char * ptr1,
+ const char * ptr2)
+{
+ MarkCacheKey *entry1, *entry2;
+
+ entry1 = (MarkCacheKey *) ptr1;
+ entry2 = (MarkCacheKey *) ptr2;
+
+ return((entry1->f != entry2->f) || (entry1->c != entry2->c));
+
+} /* end of MarkCacheCompare */
+
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees memory associated with computed table of
+ cuddBddLICMarkEdges.]
+
+ Description [Frees memory associated with computed table of
+ cuddBddLICMarkEdges. Returns ST_CONTINUE.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddLICompaction]
+
+******************************************************************************/
+static enum st_retval
+MarkCacheCleanUp(
+ char * key,
+ char * value,
+ char * arg)
+{
+ MarkCacheKey *entry;
+
+ entry = (MarkCacheKey *) key;
+ FREE(entry);
+ return ST_CONTINUE;
+
+} /* end of MarkCacheCleanUp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddSqueeze.]
+
+ Description [Performs the recursive step of Cudd_bddSqueeze. This
+ procedure exploits the fact that if we complement and swap the
+ bounds of the interval we obtain a valid solution by taking the
+ complement of the solution to the original problem. Therefore, we
+ can enforce the condition that the upper bound is always regular.
+ Returns a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddSqueeze]
+
+******************************************************************************/
+static DdNode *
+cuddBddSqueeze(
+ DdManager * dd,
+ DdNode * l,
+ DdNode * u)
+{
+ DdNode *one, *zero, *r, *lt, *le, *ut, *ue, *t, *e;
+#if 0
+ DdNode *ar;
+#endif
+ int comple = 0;
+ unsigned int topu, topl;
+ int index;
+
+ statLine(dd);
+ if (l == u) {
+ return(l);
+ }
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+ /* The only case when l == zero && u == one is at the top level,
+ ** where returning either one or zero is OK. In all other cases
+ ** the procedure will detect such a case and will perform
+ ** remapping. Therefore the order in which we test l and u at this
+ ** point is immaterial. */
+ if (l == zero) return(l);
+ if (u == one) return(u);
+
+ /* Make canonical to increase the utilization of the cache. */
+ if (Cudd_IsComplement(u)) {
+ DdNode *temp;
+ temp = Cudd_Not(l);
+ l = Cudd_Not(u);
+ u = temp;
+ comple = 1;
+ }
+ /* At this point u is regular and non-constant; l is non-constant, but
+ ** may be complemented. */
+
+ /* Here we could check the relative sizes. */
+
+ /* Check the cache. */
+ r = cuddCacheLookup2(dd, Cudd_bddSqueeze, l, u);
+ if (r != NULL) {
+ return(Cudd_NotCond(r,comple));
+ }
+
+ /* Recursive step. */
+ topu = dd->perm[u->index];
+ topl = dd->perm[Cudd_Regular(l)->index];
+ if (topu <= topl) {
+ index = u->index;
+ ut = cuddT(u); ue = cuddE(u);
+ } else {
+ index = Cudd_Regular(l)->index;
+ ut = ue = u;
+ }
+ if (topl <= topu) {
+ lt = cuddT(Cudd_Regular(l)); le = cuddE(Cudd_Regular(l));
+ if (Cudd_IsComplement(l)) {
+ lt = Cudd_Not(lt);
+ le = Cudd_Not(le);
+ }
+ } else {
+ lt = le = l;
+ }
+
+ /* If one interval is contained in the other, use the smaller
+ ** interval. This corresponds to one-sided matching. */
+ if ((lt == zero || Cudd_bddLeq(dd,lt,le)) &&
+ (ut == one || Cudd_bddLeq(dd,ue,ut))) { /* remap */
+ r = cuddBddSqueeze(dd, le, ue);
+ if (r == NULL)
+ return(NULL);
+ return(Cudd_NotCond(r,comple));
+ } else if ((le == zero || Cudd_bddLeq(dd,le,lt)) &&
+ (ue == one || Cudd_bddLeq(dd,ut,ue))) { /* remap */
+ r = cuddBddSqueeze(dd, lt, ut);
+ if (r == NULL)
+ return(NULL);
+ return(Cudd_NotCond(r,comple));
+ } else if ((le == zero || Cudd_bddLeq(dd,le,Cudd_Not(ut))) &&
+ (ue == one || Cudd_bddLeq(dd,Cudd_Not(lt),ue))) { /* c-remap */
+ t = cuddBddSqueeze(dd, lt, ut);
+ cuddRef(t);
+ if (Cudd_IsComplement(t)) {
+ r = cuddUniqueInter(dd, index, Cudd_Not(t), t);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = cuddUniqueInter(dd, index, t, Cudd_Not(t));
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ }
+ cuddDeref(t);
+ if (r == NULL)
+ return(NULL);
+ cuddCacheInsert2(dd, Cudd_bddSqueeze, l, u, r);
+ return(Cudd_NotCond(r,comple));
+ } else if ((lt == zero || Cudd_bddLeq(dd,lt,Cudd_Not(ue))) &&
+ (ut == one || Cudd_bddLeq(dd,Cudd_Not(le),ut))) { /* c-remap */
+ e = cuddBddSqueeze(dd, le, ue);
+ cuddRef(e);
+ if (Cudd_IsComplement(e)) {
+ r = cuddUniqueInter(dd, index, Cudd_Not(e), e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, e);
+ return(NULL);
+ }
+ } else {
+ r = cuddUniqueInter(dd, index, e, Cudd_Not(e));
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, e);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ }
+ cuddDeref(e);
+ if (r == NULL)
+ return(NULL);
+ cuddCacheInsert2(dd, Cudd_bddSqueeze, l, u, r);
+ return(Cudd_NotCond(r,comple));
+ }
+
+#if 0
+ /* If the two intervals intersect, take a solution from
+ ** the intersection of the intervals. This guarantees that the
+ ** splitting variable will not appear in the result.
+ ** This approach corresponds to two-sided matching, and is very
+ ** expensive. */
+ if (Cudd_bddLeq(dd,lt,ue) && Cudd_bddLeq(dd,le,ut)) {
+ DdNode *au, *al;
+ au = cuddBddAndRecur(dd,ut,ue);
+ if (au == NULL)
+ return(NULL);
+ cuddRef(au);
+ al = cuddBddAndRecur(dd,Cudd_Not(lt),Cudd_Not(le));
+ if (al == NULL) {
+ Cudd_IterDerefBdd(dd,au);
+ return(NULL);
+ }
+ cuddRef(al);
+ al = Cudd_Not(al);
+ ar = cuddBddSqueeze(dd, al, au);
+ if (ar == NULL) {
+ Cudd_IterDerefBdd(dd,au);
+ Cudd_IterDerefBdd(dd,al);
+ return(NULL);
+ }
+ cuddRef(ar);
+ Cudd_IterDerefBdd(dd,au);
+ Cudd_IterDerefBdd(dd,al);
+ } else {
+ ar = NULL;
+ }
+#endif
+
+ t = cuddBddSqueeze(dd, lt, ut);
+ if (t == NULL) {
+ return(NULL);
+ }
+ cuddRef(t);
+ e = cuddBddSqueeze(dd, le, ue);
+ if (e == NULL) {
+ Cudd_IterDerefBdd(dd,t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ if (Cudd_IsComplement(t)) {
+ t = Cudd_Not(t);
+ e = Cudd_Not(e);
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, e);
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, e);
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+
+#if 0
+ /* Check whether there is a result obtained by abstraction and whether
+ ** it is better than the one obtained by recursion. */
+ cuddRef(r);
+ if (ar != NULL) {
+ if (Cudd_DagSize(ar) <= Cudd_DagSize(r)) {
+ Cudd_IterDerefBdd(dd, r);
+ r = ar;
+ } else {
+ Cudd_IterDerefBdd(dd, ar);
+ }
+ }
+ cuddDeref(r);
+#endif
+
+ cuddCacheInsert2(dd, Cudd_bddSqueeze, l, u, r);
+ return(Cudd_NotCond(r,comple));
+
+} /* end of cuddBddSqueeze */
diff --git a/src/bdd/cudd/cuddGenetic.c b/src/bdd/cudd/cuddGenetic.c
new file mode 100644
index 00000000..8341dcbd
--- /dev/null
+++ b/src/bdd/cudd/cuddGenetic.c
@@ -0,0 +1,921 @@
+/**CFile***********************************************************************
+
+ FileName [cuddGenetic.c]
+
+ PackageName [cudd]
+
+ Synopsis [Genetic algorithm for variable reordering.]
+
+ Description [Internal procedures included in this file:
+ <ul>
+ <li> cuddGa()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> make_random()
+ <li> sift_up()
+ <li> build_dd()
+ <li> largest()
+ <li> rand_int()
+ <li> array_hash()
+ <li> array_compare()
+ <li> find_best()
+ <li> find_average_fitness()
+ <li> PMX()
+ <li> roulette()
+ </ul>
+
+ The genetic algorithm implemented here is as follows. We start with
+ the current DD order. We sift this order and use this as the
+ reference DD. We only keep 1 DD around for the entire process and
+ simply rearrange the order of this DD, storing the various orders
+ and their corresponding DD sizes. We generate more random orders to
+ build an initial population. This initial population is 3 times the
+ number of variables, with a maximum of 120. Each random order is
+ built (from the reference DD) and its size stored. Each random
+ order is also sifted to keep the DD sizes fairly small. Then a
+ crossover is performed between two orders (picked randomly) and the
+ two resulting DDs are built and sifted. For each new order, if its
+ size is smaller than any DD in the population, it is inserted into
+ the population and the DD with the largest number of nodes is thrown
+ out. The crossover process happens up to 50 times, and at this point
+ the DD in the population with the smallest size is chosen as the
+ result. This DD must then be built from the reference DD.]
+
+ SeeAlso []
+
+ Author [Curt Musfeldt, Alan Shuler, Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddGenetic.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+static int popsize; /* the size of the population */
+static int numvars; /* the number of input variables in the ckt. */
+/* storedd stores the population orders and sizes. This table has two
+** extra rows and one extras column. The two extra rows are used for the
+** offspring produced by a crossover. Each row stores one order and its
+** size. The order is stored by storing the indices of variables in the
+** order in which they appear in the order. The table is in reality a
+** one-dimensional array which is accessed via a macro to give the illusion
+** it is a two-dimensional structure.
+*/
+static int *storedd;
+static st_table *computed; /* hash table to identify existing orders */
+static int *repeat; /* how many times an order is present */
+static int large; /* stores the index of the population with
+ ** the largest number of nodes in the DD */
+static int result;
+static int cross; /* the number of crossovers to perform */
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/* macro used to access the population table as if it were a
+** two-dimensional structure.
+*/
+#define STOREDD(i,j) storedd[(i)*(numvars+1)+(j)]
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int make_random ARGS((DdManager *table, int lower));
+static int sift_up ARGS((DdManager *table, int x, int x_low));
+static int build_dd ARGS((DdManager *table, int num, int lower, int upper));
+static int largest ARGS(());
+static int rand_int ARGS((int a));
+static int array_hash ARGS((char *array, int modulus));
+static int array_compare ARGS((const char *array1, const char *array2));
+static int find_best ARGS(());
+static double find_average_fitness ARGS(());
+static int PMX ARGS((int maxvar));
+static int roulette ARGS((int *p1, int *p2));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Genetic algorithm for DD reordering.]
+
+ Description [Genetic algorithm for DD reordering.
+ The two children of a crossover will be stored in
+ storedd[popsize] and storedd[popsize+1] --- the last two slots in the
+ storedd array. (This will make comparisons and replacement easy.)
+ Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddGa(
+ DdManager * table /* manager */,
+ int lower /* lowest level to be reordered */,
+ int upper /* highest level to be reorderded */)
+{
+ int i,n,m; /* dummy/loop vars */
+ int index;
+ double average_fitness;
+ int small; /* index of smallest DD in population */
+
+ /* Do an initial sifting to produce at least one reasonable individual. */
+ if (!cuddSifting(table,lower,upper)) return(0);
+
+ /* Get the initial values. */
+ numvars = upper - lower + 1; /* number of variables to be reordered */
+ if (table->populationSize == 0) {
+ popsize = 3 * numvars; /* population size is 3 times # of vars */
+ if (popsize > 120) {
+ popsize = 120; /* Maximum population size is 120 */
+ }
+ } else {
+ popsize = table->populationSize; /* user specified value */
+ }
+ if (popsize < 4) popsize = 4; /* enforce minimum population size */
+
+ /* Allocate population table. */
+ storedd = ALLOC(int,(popsize+2)*(numvars+1));
+ if (storedd == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+
+ /* Initialize the computed table. This table is made up of two data
+ ** structures: A hash table with the key given by the order, which says
+ ** if a given order is present in the population; and the repeat
+ ** vector, which says how many copies of a given order are stored in
+ ** the population table. If there are multiple copies of an order, only
+ ** one has a repeat count greater than 1. This copy is the one pointed
+ ** by the computed table.
+ */
+ repeat = ALLOC(int,popsize);
+ if (repeat == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ FREE(storedd);
+ return(0);
+ }
+ for (i = 0; i < popsize; i++) {
+ repeat[i] = 0;
+ }
+ computed = st_init_table(array_compare,array_hash);
+ if (computed == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ FREE(storedd);
+ FREE(repeat);
+ return(0);
+ }
+
+ /* Copy the current DD and its size to the population table. */
+ for (i = 0; i < numvars; i++) {
+ STOREDD(0,i) = table->invperm[i+lower]; /* order of initial DD */
+ }
+ STOREDD(0,numvars) = table->keys - table->isolated; /* size of initial DD */
+
+ /* Store the initial order in the computed table. */
+ if (st_insert(computed,(char *)storedd,(char *) 0) == ST_OUT_OF_MEM) {
+ FREE(storedd);
+ FREE(repeat);
+ st_free_table(computed);
+ return(0);
+ }
+ repeat[0]++;
+
+ /* Insert the reverse order as second element of the population. */
+ for (i = 0; i < numvars; i++) {
+ STOREDD(1,numvars-1-i) = table->invperm[i+lower]; /* reverse order */
+ }
+
+ /* Now create the random orders. make_random fills the population
+ ** table with random permutations. The successive loop builds and sifts
+ ** the DDs for the reverse order and each random permutation, and stores
+ ** the results in the computed table.
+ */
+ if (!make_random(table,lower)) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ FREE(storedd);
+ FREE(repeat);
+ st_free_table(computed);
+ return(0);
+ }
+ for (i = 1; i < popsize; i++) {
+ result = build_dd(table,i,lower,upper); /* build and sift order */
+ if (!result) {
+ FREE(storedd);
+ FREE(repeat);
+ st_free_table(computed);
+ return(0);
+ }
+ if (st_lookup(computed,(char *)&STOREDD(i,0),(char **)&index)) {
+ repeat[index]++;
+ } else {
+ if (st_insert(computed,(char *)&STOREDD(i,0),(char *)(long)i) ==
+ ST_OUT_OF_MEM) {
+ FREE(storedd);
+ FREE(repeat);
+ st_free_table(computed);
+ return(0);
+ }
+ repeat[i]++;
+ }
+ }
+
+#if 0
+#ifdef DD_STATS
+ /* Print the initial population. */
+ (void) fprintf(table->out,"Initial population after sifting\n");
+ for (m = 0; m < popsize; m++) {
+ for (i = 0; i < numvars; i++) {
+ (void) fprintf(table->out," %2d",STOREDD(m,i));
+ }
+ (void) fprintf(table->out," : %3d (%d)\n",
+ STOREDD(m,numvars),repeat[m]);
+ }
+#endif
+#endif
+
+ small = find_best();
+ average_fitness = find_average_fitness();
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\nInitial population: best fitness = %d, average fitness %8.3f",STOREDD(small,numvars),average_fitness);
+#endif
+
+ /* Decide how many crossovers should be tried. */
+ if (table->numberXovers == 0) {
+ cross = 3*numvars;
+ if (cross > 60) { /* do a maximum of 50 crossovers */
+ cross = 60;
+ }
+ } else {
+ cross = table->numberXovers; /* use user specified value */
+ }
+
+ /* Perform the crossovers to get the best order. */
+ for (m = 0; m < cross; m++) {
+ if (!PMX(table->size)) { /* perform one crossover */
+ table->errorCode = CUDD_MEMORY_OUT;
+ FREE(storedd);
+ FREE(repeat);
+ st_free_table(computed);
+ return(0);
+ }
+ /* The offsprings are left in the last two entries of the
+ ** population table. These are now considered in turn.
+ */
+ for (i = popsize; i <= popsize+1; i++) {
+ result = build_dd(table,i,lower,upper); /* build and sift child */
+ if (!result) {
+ FREE(storedd);
+ FREE(repeat);
+ st_free_table(computed);
+ return(0);
+ }
+ large = largest(); /* find the largest DD in population */
+
+ /* If the new child is smaller than the largest DD in the current
+ ** population, enter it into the population in place of the
+ ** largest DD.
+ */
+ if (STOREDD(i,numvars) < STOREDD(large,numvars)) {
+ /* Look up the largest DD in the computed table.
+ ** Decrease its repetition count. If the repetition count
+ ** goes to 0, remove the largest DD from the computed table.
+ */
+ result = st_lookup(computed,(char *)&STOREDD(large,0),(char
+ **)&index);
+ if (!result) {
+ FREE(storedd);
+ FREE(repeat);
+ st_free_table(computed);
+ return(0);
+ }
+ repeat[index]--;
+ if (repeat[index] == 0) {
+ int *pointer = &STOREDD(index,0);
+ result = st_delete(computed, (char **)&pointer,NULL);
+ if (!result) {
+ FREE(storedd);
+ FREE(repeat);
+ st_free_table(computed);
+ return(0);
+ }
+ }
+ /* Copy the new individual to the entry of the
+ ** population table just made available and update the
+ ** computed table.
+ */
+ for (n = 0; n <= numvars; n++) {
+ STOREDD(large,n) = STOREDD(i,n);
+ }
+ if (st_lookup(computed,(char *)&STOREDD(large,0),(char
+ **)&index)) {
+ repeat[index]++;
+ } else {
+ if (st_insert(computed,(char *)&STOREDD(large,0),
+ (char *)(long)large) == ST_OUT_OF_MEM) {
+ FREE(storedd);
+ FREE(repeat);
+ st_free_table(computed);
+ return(0);
+ }
+ repeat[large]++;
+ }
+ }
+ }
+ }
+
+ /* Find the smallest DD in the population and build it;
+ ** that will be the result.
+ */
+ small = find_best();
+
+ /* Print stats on the final population. */
+#ifdef DD_STATS
+ average_fitness = find_average_fitness();
+ (void) fprintf(table->out,"\nFinal population: best fitness = %d, average fitness %8.3f",STOREDD(small,numvars),average_fitness);
+#endif
+
+ /* Clean up, build the result DD, and return. */
+ st_free_table(computed);
+ computed = NULL;
+ result = build_dd(table,small,lower,upper);
+ FREE(storedd);
+ FREE(repeat);
+ return(result);
+
+} /* end of cuddGa */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Generates the random sequences for the initial population.]
+
+ Description [Generates the random sequences for the initial population.
+ The sequences are permutations of the indices between lower and
+ upper in the current order.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+make_random(
+ DdManager * table,
+ int lower)
+{
+ int i,j; /* loop variables */
+ int *used; /* is a number already in a permutation */
+ int next; /* next random number without repetitions */
+
+ used = ALLOC(int,numvars);
+ if (used == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+#if 0
+#ifdef DD_STATS
+ (void) fprintf(table->out,"Initial population before sifting\n");
+ for (i = 0; i < 2; i++) {
+ for (j = 0; j < numvars; j++) {
+ (void) fprintf(table->out," %2d",STOREDD(i,j));
+ }
+ (void) fprintf(table->out,"\n");
+ }
+#endif
+#endif
+ for (i = 2; i < popsize; i++) {
+ for (j = 0; j < numvars; j++) {
+ used[j] = 0;
+ }
+ /* Generate a permutation of {0...numvars-1} and use it to
+ ** permute the variables in the layesr from lower to upper.
+ */
+ for (j = 0; j < numvars; j++) {
+ do {
+ next = rand_int(numvars-1);
+ } while (used[next] != 0);
+ used[next] = 1;
+ STOREDD(i,j) = table->invperm[next+lower];
+ }
+#if 0
+#ifdef DD_STATS
+ /* Print the order just generated. */
+ for (j = 0; j < numvars; j++) {
+ (void) fprintf(table->out," %2d",STOREDD(i,j));
+ }
+ (void) fprintf(table->out,"\n");
+#endif
+#endif
+ }
+ FREE(used);
+ return(1);
+
+} /* end of make_random */
+
+
+/**Function********************************************************************
+
+ Synopsis [Moves one variable up.]
+
+ Description [Takes a variable from position x and sifts it up to
+ position x_low; x_low should be less than x. Returns 1 if successful;
+ 0 otherwise]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+sift_up(
+ DdManager * table,
+ int x,
+ int x_low)
+{
+ int y;
+ int size;
+
+ y = cuddNextLow(table,x);
+ while (y >= x_low) {
+ size = cuddSwapInPlace(table,y,x);
+ if (size == 0) {
+ return(0);
+ }
+ x = y;
+ y = cuddNextLow(table,x);
+ }
+ return(1);
+
+} /* end of sift_up */
+
+
+/**Function********************************************************************
+
+ Synopsis [Builds a DD from a given order.]
+
+ Description [Builds a DD from a given order. This procedure also
+ sifts the final order and inserts into the array the size in nodes
+ of the result. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+build_dd(
+ DdManager * table,
+ int num /* the index of the individual to be built */,
+ int lower,
+ int upper)
+{
+ int i,j; /* loop vars */
+ int position;
+ int index;
+ int limit; /* how large the DD for this order can grow */
+ int size;
+
+ /* Check the computed table. If the order already exists, it
+ ** suffices to copy the size from the existing entry.
+ */
+ if (computed && st_lookup(computed,(char *)&STOREDD(num,0),(char **)&index)) {
+ STOREDD(num,numvars) = STOREDD(index,numvars);
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\nCache hit for index %d", index);
+#endif
+ return(1);
+ }
+
+ /* Stop if the DD grows 20 times larges than the reference size. */
+ limit = 20 * STOREDD(0,numvars);
+
+ /* Sift up the variables so as to build the desired permutation.
+ ** First the variable that has to be on top is sifted to the top.
+ ** Then the variable that has to occupy the secon position is sifted
+ ** up to the second position, and so on.
+ */
+ for (j = 0; j < numvars; j++) {
+ i = STOREDD(num,j);
+ position = table->perm[i];
+ result = sift_up(table,position,j+lower);
+ if (!result) return(0);
+ size = table->keys - table->isolated;
+ if (size > limit) break;
+ }
+
+ /* Sift the DD just built. */
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\n");
+#endif
+ result = cuddSifting(table,lower,upper);
+ if (!result) return(0);
+
+ /* Copy order and size to table. */
+ for (j = 0; j < numvars; j++) {
+ STOREDD(num,j) = table->invperm[lower+j];
+ }
+ STOREDD(num,numvars) = table->keys - table->isolated; /* size of new DD */
+ return(1);
+
+} /* end of build_dd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the largest DD in the population.]
+
+ Description [Finds the largest DD in the population. If an order is
+ repeated, it avoids choosing the copy that is in the computed table
+ (it has repeat[i] > 1).]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+largest(
+ )
+{
+ int i; /* loop var */
+ int big; /* temporary holder to return result */
+
+ big = 0;
+ while (repeat[big] > 1) big++;
+ for (i = big + 1; i < popsize; i++) {
+ if (STOREDD(i,numvars) >= STOREDD(big,numvars) && repeat[i] <= 1) {
+ big = i;
+ }
+ }
+ return(big);
+
+} /* end of largest */
+
+
+/**Function********************************************************************
+
+ Synopsis [Generates a random number between 0 and the integer a.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+rand_int(
+ int a)
+{
+ return(Cudd_Random() % (a+1));
+
+} /* end of rand_int */
+
+
+/**Function********************************************************************
+
+ Synopsis [Hash function for the computed table.]
+
+ Description [Hash function for the computed table. Returns the bucket
+ number.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+array_hash(
+ char * array,
+ int modulus)
+{
+ int val = 0;
+ int i;
+ int *intarray;
+
+ intarray = (int *) array;
+
+ for (i = 0; i < numvars; i++) {
+ val = val * 997 + intarray[i];
+ }
+
+ return ((val < 0) ? -val : val) % modulus;
+
+} /* end of array_hash */
+
+
+/**Function********************************************************************
+
+ Synopsis [Comparison function for the computed table.]
+
+ Description [Comparison function for the computed table. Returns 0 if
+ the two arrays are equal; 1 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+array_compare(
+ const char * array1,
+ const char * array2)
+{
+ int i;
+ int *intarray1, *intarray2;
+
+ intarray1 = (int *) array1;
+ intarray2 = (int *) array2;
+
+ for (i = 0; i < numvars; i++) {
+ if (intarray1[i] != intarray2[i]) return(1);
+ }
+ return(0);
+
+} /* end of array_compare */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the index of the fittest individual.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+find_best(
+ )
+{
+ int i,small;
+
+ small = 0;
+ for (i = 1; i < popsize; i++) {
+ if (STOREDD(i,numvars) < STOREDD(small,numvars)) {
+ small = i;
+ }
+ }
+ return(small);
+
+} /* end of find_best */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the average fitness of the population.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static double
+find_average_fitness(
+ )
+{
+ int i;
+ int total_fitness = 0;
+ double average_fitness;
+
+ for (i = 0; i < popsize; i++) {
+ total_fitness += STOREDD(i,numvars);
+ }
+ average_fitness = (double) total_fitness / (double) popsize;
+ return(average_fitness);
+
+} /* end of find_average_fitness */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the crossover between two parents.]
+
+ Description [Performs the crossover between two randomly chosen
+ parents, and creates two children, x1 and x2. Uses the Partially
+ Matched Crossover operator.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+PMX(
+ int maxvar)
+{
+ int cut1,cut2; /* the two cut positions (random) */
+ int mom,dad; /* the two randomly chosen parents */
+ int *inv1; /* inverse permutations for repair algo */
+ int *inv2;
+ int i; /* loop vars */
+ int u,v; /* aux vars */
+
+ inv1 = ALLOC(int,maxvar);
+ if (inv1 == NULL) {
+ return(0);
+ }
+ inv2 = ALLOC(int,maxvar);
+ if (inv2 == NULL) {
+ FREE(inv1);
+ return(0);
+ }
+
+ /* Choose two orders from the population using roulette wheel. */
+ if (!roulette(&mom,&dad)) {
+ FREE(inv1);
+ FREE(inv2);
+ return(0);
+ }
+
+ /* Choose two random cut positions. A cut in position i means that
+ ** the cut immediately precedes position i. If cut1 < cut2, we
+ ** exchange the middle of the two orderings; otherwise, we
+ ** exchange the beginnings and the ends.
+ */
+ cut1 = rand_int(numvars-1);
+ do {
+ cut2 = rand_int(numvars-1);
+ } while (cut1 == cut2);
+
+#if 0
+ /* Print out the parents. */
+ (void) fprintf(table->out,
+ "Crossover of %d (mom) and %d (dad) between %d and %d\n",
+ mom,dad,cut1,cut2);
+ for (i = 0; i < numvars; i++) {
+ if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
+ (void) fprintf(table->out,"%2d ",STOREDD(mom,i));
+ }
+ (void) fprintf(table->out,"\n");
+ for (i = 0; i < numvars; i++) {
+ if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
+ (void) fprintf(table->out,"%2d ",STOREDD(dad,i));
+ }
+ (void) fprintf(table->out,"\n");
+#endif
+
+ /* Initialize the inverse permutations: -1 means yet undetermined. */
+ for (i = 0; i < maxvar; i++) {
+ inv1[i] = -1;
+ inv2[i] = -1;
+ }
+
+ /* Copy the portions whithin the cuts. */
+ for (i = cut1; i != cut2; i = (i == numvars-1) ? 0 : i+1) {
+ STOREDD(popsize,i) = STOREDD(dad,i);
+ inv1[STOREDD(popsize,i)] = i;
+ STOREDD(popsize+1,i) = STOREDD(mom,i);
+ inv2[STOREDD(popsize+1,i)] = i;
+ }
+
+ /* Now apply the repair algorithm outside the cuts. */
+ for (i = cut2; i != cut1; i = (i == numvars-1 ) ? 0 : i+1) {
+ v = i;
+ do {
+ u = STOREDD(mom,v);
+ v = inv1[u];
+ } while (v != -1);
+ STOREDD(popsize,i) = u;
+ inv1[u] = i;
+ v = i;
+ do {
+ u = STOREDD(dad,v);
+ v = inv2[u];
+ } while (v != -1);
+ STOREDD(popsize+1,i) = u;
+ inv2[u] = i;
+ }
+
+#if 0
+ /* Print the results of crossover. */
+ for (i = 0; i < numvars; i++) {
+ if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
+ (void) fprintf(table->out,"%2d ",STOREDD(popsize,i));
+ }
+ (void) fprintf(table->out,"\n");
+ for (i = 0; i < numvars; i++) {
+ if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
+ (void) fprintf(table->out,"%2d ",STOREDD(popsize+1,i));
+ }
+ (void) fprintf(table->out,"\n");
+#endif
+
+ FREE(inv1);
+ FREE(inv2);
+ return(1);
+
+} /* end of PMX */
+
+
+/**Function********************************************************************
+
+ Synopsis [Selects two parents with the roulette wheel method.]
+
+ Description [Selects two distinct parents with the roulette wheel method.]
+
+ SideEffects [The indices of the selected parents are returned as side
+ effects.]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+roulette(
+ int * p1,
+ int * p2)
+{
+ double *wheel;
+ double spin;
+ int i;
+
+ wheel = ALLOC(double,popsize);
+ if (wheel == NULL) {
+ return(0);
+ }
+
+ /* The fitness of an individual is the reciprocal of its size. */
+ wheel[0] = 1.0 / (double) STOREDD(0,numvars);
+
+ for (i = 1; i < popsize; i++) {
+ wheel[i] = wheel[i-1] + 1.0 / (double) STOREDD(i,numvars);
+ }
+
+ /* Get a random number between 0 and wheel[popsize-1] (that is,
+ ** the sum of all fitness values. 2147483561 is the largest number
+ ** returned by Cudd_Random.
+ */
+ spin = wheel[numvars-1] * (double) Cudd_Random() / 2147483561.0;
+
+ /* Find the lucky element by scanning the wheel. */
+ for (i = 0; i < popsize; i++) {
+ if (spin <= wheel[i]) break;
+ }
+ *p1 = i;
+
+ /* Repeat the process for the second parent, making sure it is
+ ** distinct from the first.
+ */
+ do {
+ spin = wheel[popsize-1] * (double) Cudd_Random() / 2147483561.0;
+ for (i = 0; i < popsize; i++) {
+ if (spin <= wheel[i]) break;
+ }
+ } while (i == *p1);
+ *p2 = i;
+
+ FREE(wheel);
+ return(1);
+
+} /* end of roulette */
+
diff --git a/src/bdd/cudd/cuddGroup.c b/src/bdd/cudd/cuddGroup.c
new file mode 100644
index 00000000..f84f7881
--- /dev/null
+++ b/src/bdd/cudd/cuddGroup.c
@@ -0,0 +1,2142 @@
+/**CFile***********************************************************************
+
+ FileName [cuddGroup.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions for group sifting.]
+
+ Description [External procedures included in this file:
+ <ul>
+ <li> Cudd_MakeTreeNode()
+ </ul>
+ Internal procedures included in this file:
+ <ul>
+ <li> cuddTreeSifting()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> ddTreeSiftingAux()
+ <li> ddCountInternalMtrNodes()
+ <li> ddReorderChildren()
+ <li> ddFindNodeHiLo()
+ <li> ddUniqueCompareGroup()
+ <li> ddGroupSifting()
+ <li> ddCreateGroup()
+ <li> ddGroupSiftingAux()
+ <li> ddGroupSiftingUp()
+ <li> ddGroupSiftingDown()
+ <li> ddGroupMove()
+ <li> ddGroupMoveBackward()
+ <li> ddGroupSiftingBackward()
+ <li> ddMergeGroups()
+ <li> ddDissolveGroup()
+ <li> ddNoCheck()
+ <li> ddSecDiffCheck()
+ <li> ddExtSymmCheck()
+ <li> ddVarGroupCheck()
+ <li> ddSetVarHandled()
+ <li> ddResetVarHandled()
+ <li> ddIsVarHandled()
+ </ul>]
+
+ Author [Shipra Panda, Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/* Constants for lazy sifting */
+#define DD_NORMAL_SIFT 0
+#define DD_LAZY_SIFT 1
+
+/* Constants for sifting up and down */
+#define DD_SIFT_DOWN 0
+#define DD_SIFT_UP 1
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddGroup.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+static int *entry;
+extern int ddTotalNumberSwapping;
+#ifdef DD_STATS
+extern int ddTotalNISwaps;
+static int extsymmcalls;
+static int extsymm;
+static int secdiffcalls;
+static int secdiff;
+static int secdiffmisfire;
+#endif
+#ifdef DD_DEBUG
+static int pr = 0; /* flag to enable printing while debugging */
+ /* by depositing a 1 into it */
+#endif
+static int originalSize;
+static int originalLevel;
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int ddTreeSiftingAux ARGS((DdManager *table, MtrNode *treenode, Cudd_ReorderingType method));
+#ifdef DD_STATS
+static int ddCountInternalMtrNodes ARGS((DdManager *table, MtrNode *treenode));
+#endif
+static int ddReorderChildren ARGS((DdManager *table, MtrNode *treenode, Cudd_ReorderingType method));
+static void ddFindNodeHiLo ARGS((DdManager *table, MtrNode *treenode, int *lower, int *upper));
+static int ddUniqueCompareGroup ARGS((int *ptrX, int *ptrY));
+static int ddGroupSifting ARGS((DdManager *table, int lower, int upper, int (*checkFunction)(DdManager *, int, int), int lazyFlag));
+static void ddCreateGroup ARGS((DdManager *table, int x, int y));
+static int ddGroupSiftingAux ARGS((DdManager *table, int x, int xLow, int xHigh, int (*checkFunction)(DdManager *, int, int), int lazyFlag));
+static int ddGroupSiftingUp ARGS((DdManager *table, int y, int xLow, int (*checkFunction)(DdManager *, int, int), Move **moves));
+static int ddGroupSiftingDown ARGS((DdManager *table, int x, int xHigh, int (*checkFunction)(DdManager *, int, int), Move **moves));
+static int ddGroupMove ARGS((DdManager *table, int x, int y, Move **moves));
+static int ddGroupMoveBackward ARGS((DdManager *table, int x, int y));
+static int ddGroupSiftingBackward ARGS((DdManager *table, Move *moves, int size, int upFlag, int lazyFlag));
+static void ddMergeGroups ARGS((DdManager *table, MtrNode *treenode, int low, int high));
+static void ddDissolveGroup ARGS((DdManager *table, int x, int y));
+static int ddNoCheck ARGS((DdManager *table, int x, int y));
+static int ddSecDiffCheck ARGS((DdManager *table, int x, int y));
+static int ddExtSymmCheck ARGS((DdManager *table, int x, int y));
+static int ddVarGroupCheck ARGS((DdManager * table, int x, int y));
+static int ddSetVarHandled ARGS((DdManager *dd, int index));
+static int ddResetVarHandled ARGS((DdManager *dd, int index));
+static int ddIsVarHandled ARGS((DdManager *dd, int index));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Creates a new variable group.]
+
+ Description [Creates a new variable group. The group starts at
+ variable and contains size variables. The parameter low is the index
+ of the first variable. If the variable already exists, its current
+ position in the order is known to the manager. If the variable does
+ not exist yet, the position is assumed to be the same as the index.
+ The group tree is created if it does not exist yet.
+ Returns a pointer to the group if successful; NULL otherwise.]
+
+ SideEffects [The variable tree is changed.]
+
+ SeeAlso [Cudd_MakeZddTreeNode]
+
+******************************************************************************/
+MtrNode *
+Cudd_MakeTreeNode(
+ DdManager * dd /* manager */,
+ unsigned int low /* index of the first group variable */,
+ unsigned int size /* number of variables in the group */,
+ unsigned int type /* MTR_DEFAULT or MTR_FIXED */)
+{
+ MtrNode *group;
+ MtrNode *tree;
+ unsigned int level;
+
+ /* If the variable does not exist yet, the position is assumed to be
+ ** the same as the index. Therefore, applications that rely on
+ ** Cudd_bddNewVarAtLevel or Cudd_addNewVarAtLevel to create new
+ ** variables have to create the variables before they group them.
+ */
+ level = (low < (unsigned int) dd->size) ? dd->perm[low] : low;
+
+ if (level + size - 1> (int) MTR_MAXHIGH)
+ return(NULL);
+
+ /* If the tree does not exist yet, create it. */
+ tree = dd->tree;
+ if (tree == NULL) {
+ dd->tree = tree = Mtr_InitGroupTree(0, dd->size);
+ if (tree == NULL)
+ return(NULL);
+ tree->index = dd->invperm[0];
+ }
+
+ /* Extend the upper bound of the tree if necessary. This allows the
+ ** application to create groups even before the variables are created.
+ */
+ tree->size = ddMax(tree->size, ddMax(level + size, (unsigned) dd->size));
+
+ /* Create the group. */
+ group = Mtr_MakeGroup(tree, level, size, type);
+ if (group == NULL)
+ return(NULL);
+
+ /* Initialize the index field to the index of the variable currently
+ ** in position low. This field will be updated by the reordering
+ ** procedure to provide a handle to the group once it has been moved.
+ */
+ group->index = (MtrHalfWord) low;
+
+ return(group);
+
+} /* end of Cudd_MakeTreeNode */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Tree sifting algorithm.]
+
+ Description [Tree sifting algorithm. Assumes that a tree representing
+ a group hierarchy is passed as a parameter. It then reorders each
+ group in postorder fashion by calling ddTreeSiftingAux. Assumes that
+ no dead nodes are present. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+int
+cuddTreeSifting(
+ DdManager * table /* DD table */,
+ Cudd_ReorderingType method /* reordering method for the groups of leaves */)
+{
+ int i;
+ int nvars;
+ int result;
+ int tempTree;
+
+ /* If no tree is provided we create a temporary one in which all
+ ** variables are in a single group. After reordering this tree is
+ ** destroyed.
+ */
+ tempTree = table->tree == NULL;
+ if (tempTree) {
+ table->tree = Mtr_InitGroupTree(0,table->size);
+ table->tree->index = table->invperm[0];
+ }
+ nvars = table->size;
+
+#ifdef DD_DEBUG
+ if (pr > 0 && !tempTree) (void) fprintf(table->out,"cuddTreeSifting:");
+ Mtr_PrintGroups(table->tree,pr <= 0);
+#endif
+
+#ifdef DD_STATS
+ extsymmcalls = 0;
+ extsymm = 0;
+ secdiffcalls = 0;
+ secdiff = 0;
+ secdiffmisfire = 0;
+
+ (void) fprintf(table->out,"\n");
+ if (!tempTree)
+ (void) fprintf(table->out,"#:IM_NODES %8d: group tree nodes\n",
+ ddCountInternalMtrNodes(table,table->tree));
+#endif
+
+ /* Initialize the group of each subtable to itself. Initially
+ ** there are no groups. Groups are created according to the tree
+ ** structure in postorder fashion.
+ */
+ for (i = 0; i < nvars; i++)
+ table->subtables[i].next = i;
+
+
+ /* Reorder. */
+ result = ddTreeSiftingAux(table, table->tree, method);
+
+#ifdef DD_STATS /* print stats */
+ if (!tempTree && method == CUDD_REORDER_GROUP_SIFT &&
+ (table->groupcheck == CUDD_GROUP_CHECK7 ||
+ table->groupcheck == CUDD_GROUP_CHECK5)) {
+ (void) fprintf(table->out,"\nextsymmcalls = %d\n",extsymmcalls);
+ (void) fprintf(table->out,"extsymm = %d",extsymm);
+ }
+ if (!tempTree && method == CUDD_REORDER_GROUP_SIFT &&
+ table->groupcheck == CUDD_GROUP_CHECK7) {
+ (void) fprintf(table->out,"\nsecdiffcalls = %d\n",secdiffcalls);
+ (void) fprintf(table->out,"secdiff = %d\n",secdiff);
+ (void) fprintf(table->out,"secdiffmisfire = %d",secdiffmisfire);
+ }
+#endif
+
+ if (tempTree)
+ Cudd_FreeTree(table);
+ return(result);
+
+} /* end of cuddTreeSifting */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Visits the group tree and reorders each group.]
+
+ Description [Recursively visits the group tree and reorders each
+ group in postorder fashion. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddTreeSiftingAux(
+ DdManager * table,
+ MtrNode * treenode,
+ Cudd_ReorderingType method)
+{
+ MtrNode *auxnode;
+ int res;
+ Cudd_AggregationType saveCheck;
+
+#ifdef DD_DEBUG
+ Mtr_PrintGroups(treenode,1);
+#endif
+
+ auxnode = treenode;
+ while (auxnode != NULL) {
+ if (auxnode->child != NULL) {
+ if (!ddTreeSiftingAux(table, auxnode->child, method))
+ return(0);
+ saveCheck = table->groupcheck;
+ table->groupcheck = CUDD_NO_CHECK;
+ if (method != CUDD_REORDER_LAZY_SIFT)
+ res = ddReorderChildren(table, auxnode, CUDD_REORDER_GROUP_SIFT);
+ else
+ res = ddReorderChildren(table, auxnode, CUDD_REORDER_LAZY_SIFT);
+ table->groupcheck = saveCheck;
+
+ if (res == 0)
+ return(0);
+ } else if (auxnode->size > 1) {
+ if (!ddReorderChildren(table, auxnode, method))
+ return(0);
+ }
+ auxnode = auxnode->younger;
+ }
+
+ return(1);
+
+} /* end of ddTreeSiftingAux */
+
+
+#ifdef DD_STATS
+/**Function********************************************************************
+
+ Synopsis [Counts the number of internal nodes of the group tree.]
+
+ Description [Counts the number of internal nodes of the group tree.
+ Returns the count.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddCountInternalMtrNodes(
+ DdManager * table,
+ MtrNode * treenode)
+{
+ MtrNode *auxnode;
+ int count,nodeCount;
+
+
+ nodeCount = 0;
+ auxnode = treenode;
+ while (auxnode != NULL) {
+ if (!(MTR_TEST(auxnode,MTR_TERMINAL))) {
+ nodeCount++;
+ count = ddCountInternalMtrNodes(table,auxnode->child);
+ nodeCount += count;
+ }
+ auxnode = auxnode->younger;
+ }
+
+ return(nodeCount);
+
+} /* end of ddCountInternalMtrNodes */
+#endif
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders the children of a group tree node according to
+ the options.]
+
+ Description [Reorders the children of a group tree node according to
+ the options. After reordering puts all the variables in the group
+ and/or its descendents in a single group. This allows hierarchical
+ reordering. If the variables in the group do not exist yet, simply
+ does nothing. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddReorderChildren(
+ DdManager * table,
+ MtrNode * treenode,
+ Cudd_ReorderingType method)
+{
+ int lower;
+ int upper;
+ int result;
+ unsigned int initialSize;
+
+ ddFindNodeHiLo(table,treenode,&lower,&upper);
+ /* If upper == -1 these variables do not exist yet. */
+ if (upper == -1)
+ return(1);
+
+ if (treenode->flags == MTR_FIXED) {
+ result = 1;
+ } else {
+#ifdef DD_STATS
+ (void) fprintf(table->out," ");
+#endif
+ switch (method) {
+ case CUDD_REORDER_RANDOM:
+ case CUDD_REORDER_RANDOM_PIVOT:
+ result = cuddSwapping(table,lower,upper,method);
+ break;
+ case CUDD_REORDER_SIFT:
+ result = cuddSifting(table,lower,upper);
+ break;
+ case CUDD_REORDER_SIFT_CONVERGE:
+ do {
+ initialSize = table->keys - table->isolated;
+ result = cuddSifting(table,lower,upper);
+ if (initialSize <= table->keys - table->isolated)
+ break;
+#ifdef DD_STATS
+ else
+ (void) fprintf(table->out,"\n");
+#endif
+ } while (result != 0);
+ break;
+ case CUDD_REORDER_SYMM_SIFT:
+ result = cuddSymmSifting(table,lower,upper);
+ break;
+ case CUDD_REORDER_SYMM_SIFT_CONV:
+ result = cuddSymmSiftingConv(table,lower,upper);
+ break;
+ case CUDD_REORDER_GROUP_SIFT:
+ if (table->groupcheck == CUDD_NO_CHECK) {
+ result = ddGroupSifting(table,lower,upper,ddNoCheck,
+ DD_NORMAL_SIFT);
+ } else if (table->groupcheck == CUDD_GROUP_CHECK5) {
+ result = ddGroupSifting(table,lower,upper,ddExtSymmCheck,
+ DD_NORMAL_SIFT);
+ } else if (table->groupcheck == CUDD_GROUP_CHECK7) {
+ result = ddGroupSifting(table,lower,upper,ddExtSymmCheck,
+ DD_NORMAL_SIFT);
+ } else {
+ (void) fprintf(table->err,
+ "Unknown group ckecking method\n");
+ result = 0;
+ }
+ break;
+ case CUDD_REORDER_GROUP_SIFT_CONV:
+ do {
+ initialSize = table->keys - table->isolated;
+ if (table->groupcheck == CUDD_NO_CHECK) {
+ result = ddGroupSifting(table,lower,upper,ddNoCheck,
+ DD_NORMAL_SIFT);
+ } else if (table->groupcheck == CUDD_GROUP_CHECK5) {
+ result = ddGroupSifting(table,lower,upper,ddExtSymmCheck,
+ DD_NORMAL_SIFT);
+ } else if (table->groupcheck == CUDD_GROUP_CHECK7) {
+ result = ddGroupSifting(table,lower,upper,ddExtSymmCheck,
+ DD_NORMAL_SIFT);
+ } else {
+ (void) fprintf(table->err,
+ "Unknown group ckecking method\n");
+ result = 0;
+ }
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\n");
+#endif
+ result = cuddWindowReorder(table,lower,upper,
+ CUDD_REORDER_WINDOW4);
+ if (initialSize <= table->keys - table->isolated)
+ break;
+#ifdef DD_STATS
+ else
+ (void) fprintf(table->out,"\n");
+#endif
+ } while (result != 0);
+ break;
+ case CUDD_REORDER_WINDOW2:
+ case CUDD_REORDER_WINDOW3:
+ case CUDD_REORDER_WINDOW4:
+ case CUDD_REORDER_WINDOW2_CONV:
+ case CUDD_REORDER_WINDOW3_CONV:
+ case CUDD_REORDER_WINDOW4_CONV:
+ result = cuddWindowReorder(table,lower,upper,method);
+ break;
+ case CUDD_REORDER_ANNEALING:
+ result = cuddAnnealing(table,lower,upper);
+ break;
+ case CUDD_REORDER_GENETIC:
+ result = cuddGa(table,lower,upper);
+ break;
+ case CUDD_REORDER_LINEAR:
+ result = cuddLinearAndSifting(table,lower,upper);
+ break;
+ case CUDD_REORDER_LINEAR_CONVERGE:
+ do {
+ initialSize = table->keys - table->isolated;
+ result = cuddLinearAndSifting(table,lower,upper);
+ if (initialSize <= table->keys - table->isolated)
+ break;
+#ifdef DD_STATS
+ else
+ (void) fprintf(table->out,"\n");
+#endif
+ } while (result != 0);
+ break;
+ case CUDD_REORDER_EXACT:
+ result = cuddExact(table,lower,upper);
+ break;
+ case CUDD_REORDER_LAZY_SIFT:
+ result = ddGroupSifting(table,lower,upper,ddVarGroupCheck,
+ DD_LAZY_SIFT);
+ break;
+ default:
+ return(0);
+ }
+ }
+
+ /* Create a single group for all the variables that were sifted,
+ ** so that they will be treated as a single block by successive
+ ** invocations of ddGroupSifting.
+ */
+ ddMergeGroups(table,treenode,lower,upper);
+
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,"ddReorderChildren:");
+#endif
+
+ return(result);
+
+} /* end of ddReorderChildren */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the lower and upper bounds of the group represented
+ by treenode.]
+
+ Description [Finds the lower and upper bounds of the group
+ represented by treenode. From the index and size fields we need to
+ derive the current positions, and find maximum and minimum.]
+
+ SideEffects [The bounds are returned as side effects.]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+ddFindNodeHiLo(
+ DdManager * table,
+ MtrNode * treenode,
+ int * lower,
+ int * upper)
+{
+ int low;
+ int high;
+
+ /* Check whether no variables in this group already exist.
+ ** If so, return immediately. The calling procedure will know from
+ ** the values of upper that no reordering is needed.
+ */
+ if ((int) treenode->low >= table->size) {
+ *lower = table->size;
+ *upper = -1;
+ return;
+ }
+
+ *lower = low = (unsigned int) table->perm[treenode->index];
+ high = (int) (low + treenode->size - 1);
+
+ if (high >= table->size) {
+ /* This is the case of a partially existing group. The aim is to
+ ** reorder as many variables as safely possible. If the tree
+ ** node is terminal, we just reorder the subset of the group
+ ** that is currently in existence. If the group has
+ ** subgroups, then we only reorder those subgroups that are
+ ** fully instantiated. This way we avoid breaking up a group.
+ */
+ MtrNode *auxnode = treenode->child;
+ if (auxnode == NULL) {
+ *upper = (unsigned int) table->size - 1;
+ } else {
+ /* Search the subgroup that strands the table->size line.
+ ** If the first group starts at 0 and goes past table->size
+ ** upper will get -1, thus correctly signaling that no reordering
+ ** should take place.
+ */
+ while (auxnode != NULL) {
+ int thisLower = table->perm[auxnode->low];
+ int thisUpper = thisLower + auxnode->size - 1;
+ if (thisUpper >= table->size && thisLower < table->size)
+ *upper = (unsigned int) thisLower - 1;
+ auxnode = auxnode->younger;
+ }
+ }
+ } else {
+ /* Normal case: All the variables of the group exist. */
+ *upper = (unsigned int) high;
+ }
+
+#ifdef DD_DEBUG
+ /* Make sure that all variables in group are contiguous. */
+ assert(treenode->size >= *upper - *lower + 1);
+#endif
+
+ return;
+
+} /* end of ddFindNodeHiLo */
+
+
+/**Function********************************************************************
+
+ Synopsis [Comparison function used by qsort.]
+
+ Description [Comparison function used by qsort to order the variables
+ according to the number of keys in the subtables. Returns the
+ difference in number of keys between the two variables being
+ compared.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddUniqueCompareGroup(
+ int * ptrX,
+ int * ptrY)
+{
+#if 0
+ if (entry[*ptrY] == entry[*ptrX]) {
+ return((*ptrX) - (*ptrY));
+ }
+#endif
+ return(entry[*ptrY] - entry[*ptrX]);
+
+} /* end of ddUniqueCompareGroup */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts from treenode->low to treenode->high.]
+
+ Description [Sifts from treenode->low to treenode->high. If
+ croupcheck == CUDD_GROUP_CHECK7, it checks for group creation at the
+ end of the initial sifting. If a group is created, it is then sifted
+ again. After sifting one variable, the group that contains it is
+ dissolved. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddGroupSifting(
+ DdManager * table,
+ int lower,
+ int upper,
+ int (*checkFunction)(DdManager *, int, int),
+ int lazyFlag)
+{
+ int *var;
+ int i,j,x,xInit;
+ int nvars;
+ int classes;
+ int result;
+ int *sifted;
+ int merged;
+ int dissolve;
+#ifdef DD_STATS
+ unsigned previousSize;
+#endif
+ int xindex;
+
+ nvars = table->size;
+
+ /* Order variables to sift. */
+ entry = NULL;
+ sifted = NULL;
+ var = ALLOC(int,nvars);
+ if (var == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto ddGroupSiftingOutOfMem;
+ }
+ entry = ALLOC(int,nvars);
+ if (entry == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto ddGroupSiftingOutOfMem;
+ }
+ sifted = ALLOC(int,nvars);
+ if (sifted == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto ddGroupSiftingOutOfMem;
+ }
+
+ /* Here we consider only one representative for each group. */
+ for (i = 0, classes = 0; i < nvars; i++) {
+ sifted[i] = 0;
+ x = table->perm[i];
+ if ((unsigned) x >= table->subtables[x].next) {
+ entry[i] = table->subtables[x].keys;
+ var[classes] = i;
+ classes++;
+ }
+ }
+
+ qsort((void *)var,classes,sizeof(int),
+ (int (*)(const void *, const void *)) ddUniqueCompareGroup);
+
+ if (lazyFlag) {
+ for (i = 0; i < nvars; i ++) {
+ ddResetVarHandled(table, i);
+ }
+ }
+
+ /* Now sift. */
+ for (i = 0; i < ddMin(table->siftMaxVar,classes); i++) {
+ if (ddTotalNumberSwapping >= table->siftMaxSwap)
+ break;
+ xindex = var[i];
+ if (sifted[xindex] == 1) /* variable already sifted as part of group */
+ continue;
+ x = table->perm[xindex]; /* find current level of this variable */
+
+ if (x < lower || x > upper || table->subtables[x].bindVar == 1)
+ continue;
+#ifdef DD_STATS
+ previousSize = table->keys - table->isolated;
+#endif
+#ifdef DD_DEBUG
+ /* x is bottom of group */
+ assert((unsigned) x >= table->subtables[x].next);
+#endif
+ if ((unsigned) x == table->subtables[x].next) {
+ dissolve = 1;
+ result = ddGroupSiftingAux(table,x,lower,upper,checkFunction,
+ lazyFlag);
+ } else {
+ dissolve = 0;
+ result = ddGroupSiftingAux(table,x,lower,upper,ddNoCheck,lazyFlag);
+ }
+ if (!result) goto ddGroupSiftingOutOfMem;
+
+ /* check for aggregation */
+ merged = 0;
+ if (lazyFlag == 0 && table->groupcheck == CUDD_GROUP_CHECK7) {
+ x = table->perm[xindex]; /* find current level */
+ if ((unsigned) x == table->subtables[x].next) { /* not part of a group */
+ if (x != upper && sifted[table->invperm[x+1]] == 0 &&
+ (unsigned) x+1 == table->subtables[x+1].next) {
+ if (ddSecDiffCheck(table,x,x+1)) {
+ merged =1;
+ ddCreateGroup(table,x,x+1);
+ }
+ }
+ if (x != lower && sifted[table->invperm[x-1]] == 0 &&
+ (unsigned) x-1 == table->subtables[x-1].next) {
+ if (ddSecDiffCheck(table,x-1,x)) {
+ merged =1;
+ ddCreateGroup(table,x-1,x);
+ }
+ }
+ }
+ }
+
+ if (merged) { /* a group was created */
+ /* move x to bottom of group */
+ while ((unsigned) x < table->subtables[x].next)
+ x = table->subtables[x].next;
+ /* sift */
+ result = ddGroupSiftingAux(table,x,lower,upper,ddNoCheck,lazyFlag);
+ if (!result) goto ddGroupSiftingOutOfMem;
+#ifdef DD_STATS
+ if (table->keys < previousSize + table->isolated) {
+ (void) fprintf(table->out,"_");
+ } else if (table->keys > previousSize + table->isolated) {
+ (void) fprintf(table->out,"^");
+ } else {
+ (void) fprintf(table->out,"*");
+ }
+ fflush(table->out);
+ } else {
+ if (table->keys < previousSize + table->isolated) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keys > previousSize + table->isolated) {
+ (void) fprintf(table->out,"+");
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+
+ /* Mark variables in the group just sifted. */
+ x = table->perm[xindex];
+ if ((unsigned) x != table->subtables[x].next) {
+ xInit = x;
+ do {
+ j = table->invperm[x];
+ sifted[j] = 1;
+ x = table->subtables[x].next;
+ } while (x != xInit);
+
+ /* Dissolve the group if it was created. */
+ if (lazyFlag == 0 && dissolve) {
+ do {
+ j = table->subtables[x].next;
+ table->subtables[x].next = x;
+ x = j;
+ } while (x != xInit);
+ }
+ }
+
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,"ddGroupSifting:");
+#endif
+
+ if (lazyFlag) ddSetVarHandled(table, xindex);
+ } /* for */
+
+ FREE(sifted);
+ FREE(var);
+ FREE(entry);
+
+ return(1);
+
+ddGroupSiftingOutOfMem:
+ if (entry != NULL) FREE(entry);
+ if (var != NULL) FREE(var);
+ if (sifted != NULL) FREE(sifted);
+
+ return(0);
+
+} /* end of ddGroupSifting */
+
+
+/**Function********************************************************************
+
+ Synopsis [Creates a group encompassing variables from x to y in the
+ DD table.]
+
+ Description [Creates a group encompassing variables from x to y in the
+ DD table. In the current implementation it must be y == x+1.
+ Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static void
+ddCreateGroup(
+ DdManager * table,
+ int x,
+ int y)
+{
+ int gybot;
+
+#ifdef DD_DEBUG
+ assert(y == x+1);
+#endif
+
+ /* Find bottom of second group. */
+ gybot = y;
+ while ((unsigned) gybot < table->subtables[gybot].next)
+ gybot = table->subtables[gybot].next;
+
+ /* Link groups. */
+ table->subtables[x].next = y;
+ table->subtables[gybot].next = x;
+
+ return;
+
+} /* ddCreateGroup */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts one variable up and down until it has taken all
+ positions. Checks for aggregation.]
+
+ Description [Sifts one variable up and down until it has taken all
+ positions. Checks for aggregation. There may be at most two sweeps,
+ even if the group grows. Assumes that x is either an isolated
+ variable, or it is the bottom of a group. All groups may not have
+ been found. The variable being moved is returned to the best position
+ seen during sifting. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddGroupSiftingAux(
+ DdManager * table,
+ int x,
+ int xLow,
+ int xHigh,
+ int (*checkFunction)(DdManager *, int, int),
+ int lazyFlag)
+{
+ Move *move;
+ Move *moves; /* list of moves */
+ int initialSize;
+ int result;
+ int y;
+ int topbot;
+
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,
+ "ddGroupSiftingAux from %d to %d\n",xLow,xHigh);
+ assert((unsigned) x >= table->subtables[x].next); /* x is bottom of group */
+#endif
+
+ initialSize = table->keys - table->isolated;
+ moves = NULL;
+
+ originalSize = initialSize; /* for lazy sifting */
+
+ /* If we have a singleton, we check for aggregation in both
+ ** directions before we sift.
+ */
+ if ((unsigned) x == table->subtables[x].next) {
+ /* Will go down first, unless x == xHigh:
+ ** Look for aggregation above x.
+ */
+ for (y = x; y > xLow; y--) {
+ if (!checkFunction(table,y-1,y))
+ break;
+ topbot = table->subtables[y-1].next; /* find top of y-1's group */
+ table->subtables[y-1].next = y;
+ table->subtables[x].next = topbot; /* x is bottom of group so its */
+ /* next is top of y-1's group */
+ y = topbot + 1; /* add 1 for y--; new y is top of group */
+ }
+ /* Will go up first unless x == xlow:
+ ** Look for aggregation below x.
+ */
+ for (y = x; y < xHigh; y++) {
+ if (!checkFunction(table,y,y+1))
+ break;
+ /* find bottom of y+1's group */
+ topbot = y + 1;
+ while ((unsigned) topbot < table->subtables[topbot].next) {
+ topbot = table->subtables[topbot].next;
+ }
+ table->subtables[topbot].next = table->subtables[y].next;
+ table->subtables[y].next = y + 1;
+ y = topbot - 1; /* subtract 1 for y++; new y is bottom of group */
+ }
+ }
+
+ /* Now x may be in the middle of a group.
+ ** Find bottom of x's group.
+ */
+ while ((unsigned) x < table->subtables[x].next)
+ x = table->subtables[x].next;
+
+ originalLevel = x; /* for lazy sifting */
+
+ if (x == xLow) { /* Sift down */
+#ifdef DD_DEBUG
+ /* x must be a singleton */
+ assert((unsigned) x == table->subtables[x].next);
+#endif
+ if (x == xHigh) return(1); /* just one variable */
+
+ if (!ddGroupSiftingDown(table,x,xHigh,checkFunction,&moves))
+ goto ddGroupSiftingAuxOutOfMem;
+ /* at this point x == xHigh, unless early term */
+
+ /* move backward and stop at best position */
+ result = ddGroupSiftingBackward(table,moves,initialSize,
+ DD_SIFT_DOWN,lazyFlag);
+#ifdef DD_DEBUG
+ assert(table->keys - table->isolated <= (unsigned) initialSize);
+#endif
+ if (!result) goto ddGroupSiftingAuxOutOfMem;
+
+ } else if (cuddNextHigh(table,x) > xHigh) { /* Sift up */
+#ifdef DD_DEBUG
+ /* x is bottom of group */
+ assert((unsigned) x >= table->subtables[x].next);
+#endif
+ /* Find top of x's group */
+ x = table->subtables[x].next;
+
+ if (!ddGroupSiftingUp(table,x,xLow,checkFunction,&moves))
+ goto ddGroupSiftingAuxOutOfMem;
+ /* at this point x == xLow, unless early term */
+
+ /* move backward and stop at best position */
+ result = ddGroupSiftingBackward(table,moves,initialSize,
+ DD_SIFT_UP,lazyFlag);
+#ifdef DD_DEBUG
+ assert(table->keys - table->isolated <= (unsigned) initialSize);
+#endif
+ if (!result) goto ddGroupSiftingAuxOutOfMem;
+
+ } else if (x - xLow > xHigh - x) { /* must go down first: shorter */
+ if (!ddGroupSiftingDown(table,x,xHigh,checkFunction,&moves))
+ goto ddGroupSiftingAuxOutOfMem;
+ /* at this point x == xHigh, unless early term */
+
+ /* Find top of group */
+ if (moves) {
+ x = moves->y;
+ }
+ while ((unsigned) x < table->subtables[x].next)
+ x = table->subtables[x].next;
+ x = table->subtables[x].next;
+#ifdef DD_DEBUG
+ /* x should be the top of a group */
+ assert((unsigned) x <= table->subtables[x].next);
+#endif
+
+ if (!ddGroupSiftingUp(table,x,xLow,checkFunction,&moves))
+ goto ddGroupSiftingAuxOutOfMem;
+
+ /* move backward and stop at best position */
+ result = ddGroupSiftingBackward(table,moves,initialSize,
+ DD_SIFT_UP,lazyFlag);
+#ifdef DD_DEBUG
+ assert(table->keys - table->isolated <= (unsigned) initialSize);
+#endif
+ if (!result) goto ddGroupSiftingAuxOutOfMem;
+
+ } else { /* moving up first: shorter */
+ /* Find top of x's group */
+ x = table->subtables[x].next;
+
+ if (!ddGroupSiftingUp(table,x,xLow,checkFunction,&moves))
+ goto ddGroupSiftingAuxOutOfMem;
+ /* at this point x == xHigh, unless early term */
+
+ if (moves) {
+ x = moves->x;
+ }
+ while ((unsigned) x < table->subtables[x].next)
+ x = table->subtables[x].next;
+#ifdef DD_DEBUG
+ /* x is bottom of a group */
+ assert((unsigned) x >= table->subtables[x].next);
+#endif
+
+ if (!ddGroupSiftingDown(table,x,xHigh,checkFunction,&moves))
+ goto ddGroupSiftingAuxOutOfMem;
+
+ /* move backward and stop at best position */
+ result = ddGroupSiftingBackward(table,moves,initialSize,
+ DD_SIFT_DOWN,lazyFlag);
+#ifdef DD_DEBUG
+ assert(table->keys - table->isolated <= (unsigned) initialSize);
+#endif
+ if (!result) goto ddGroupSiftingAuxOutOfMem;
+ }
+
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+
+ return(1);
+
+ddGroupSiftingAuxOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+
+ return(0);
+
+} /* end of ddGroupSiftingAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts up a variable until either it reaches position xLow
+ or the size of the DD heap increases too much.]
+
+ Description [Sifts up a variable until either it reaches position
+ xLow or the size of the DD heap increases too much. Assumes that y is
+ the top of a group (or a singleton). Checks y for aggregation to the
+ adjacent variables. Records all the moves that are appended to the
+ list of moves received as input and returned as a side effect.
+ Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddGroupSiftingUp(
+ DdManager * table,
+ int y,
+ int xLow,
+ int (*checkFunction)(DdManager *, int, int),
+ Move ** moves)
+{
+ Move *move;
+ int x;
+ int size;
+ int i;
+ int gxtop,gybot;
+ int limitSize;
+ int xindex, yindex;
+ int zindex;
+ int z;
+ int isolated;
+ int L; /* lower bound on DD size */
+#ifdef DD_DEBUG
+ int checkL;
+#endif
+
+ yindex = table->invperm[y];
+
+ /* Initialize the lower bound.
+ ** The part of the DD below the bottom of y's group will not change.
+ ** The part of the DD above y that does not interact with any
+ ** variable of y's group will not change.
+ ** The rest may vanish in the best case, except for
+ ** the nodes at level xLow, which will not vanish, regardless.
+ ** What we use here is not really a lower bound, because we ignore
+ ** the interactions with all variables except y.
+ */
+ limitSize = L = table->keys - table->isolated;
+ gybot = y;
+ while ((unsigned) gybot < table->subtables[gybot].next)
+ gybot = table->subtables[gybot].next;
+ for (z = xLow + 1; z <= gybot; z++) {
+ zindex = table->invperm[z];
+ if (zindex == yindex || cuddTestInteract(table,zindex,yindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ L -= table->subtables[z].keys - isolated;
+ }
+ }
+
+ originalLevel = y; /* for lazy sifting */
+
+ x = cuddNextLow(table,y);
+ while (x >= xLow && L <= limitSize) {
+#ifdef DD_DEBUG
+ gybot = y;
+ while ((unsigned) gybot < table->subtables[gybot].next)
+ gybot = table->subtables[gybot].next;
+ checkL = table->keys - table->isolated;
+ for (z = xLow + 1; z <= gybot; z++) {
+ zindex = table->invperm[z];
+ if (zindex == yindex || cuddTestInteract(table,zindex,yindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ checkL -= table->subtables[z].keys - isolated;
+ }
+ }
+ if (pr > 0 && L != checkL) {
+ (void) fprintf(table->out,
+ "Inaccurate lower bound: L = %d checkL = %d\n",
+ L, checkL);
+ }
+#endif
+ gxtop = table->subtables[x].next;
+ if (checkFunction(table,x,y)) {
+ /* Group found, attach groups */
+ table->subtables[x].next = y;
+ i = table->subtables[y].next;
+ while (table->subtables[i].next != (unsigned) y)
+ i = table->subtables[i].next;
+ table->subtables[i].next = gxtop;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddGroupSiftingUpOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->flags = MTR_NEWNODE;
+ move->size = table->keys - table->isolated;
+ move->next = *moves;
+ *moves = move;
+ } else if (table->subtables[x].next == (unsigned) x &&
+ table->subtables[y].next == (unsigned) y) {
+ /* x and y are self groups */
+ xindex = table->invperm[x];
+ size = cuddSwapInPlace(table,x,y);
+#ifdef DD_DEBUG
+ assert(table->subtables[x].next == (unsigned) x);
+ assert(table->subtables[y].next == (unsigned) y);
+#endif
+ if (size == 0) goto ddGroupSiftingUpOutOfMem;
+ /* Update the lower bound. */
+ if (cuddTestInteract(table,xindex,yindex)) {
+ isolated = table->vars[xindex]->ref == 1;
+ L += table->subtables[y].keys - isolated;
+ }
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddGroupSiftingUpOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->flags = MTR_DEFAULT;
+ move->size = size;
+ move->next = *moves;
+ *moves = move;
+
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,
+ "ddGroupSiftingUp (2 single groups):\n");
+#endif
+ if ((double) size > (double) limitSize * table->maxGrowth)
+ return(1);
+ if (size < limitSize) limitSize = size;
+ } else { /* Group move */
+ size = ddGroupMove(table,x,y,moves);
+ if (size == 0) goto ddGroupSiftingUpOutOfMem;
+ /* Update the lower bound. */
+ z = (*moves)->y;
+ do {
+ zindex = table->invperm[z];
+ if (cuddTestInteract(table,zindex,yindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ L += table->subtables[z].keys - isolated;
+ }
+ z = table->subtables[z].next;
+ } while (z != (int) (*moves)->y);
+ if ((double) size > (double) limitSize * table->maxGrowth)
+ return(1);
+ if (size < limitSize) limitSize = size;
+ }
+ y = gxtop;
+ x = cuddNextLow(table,y);
+ }
+
+ return(1);
+
+ddGroupSiftingUpOutOfMem:
+ while (*moves != NULL) {
+ move = (*moves)->next;
+ cuddDeallocNode(table, (DdNode *) *moves);
+ *moves = move;
+ }
+ return(0);
+
+} /* end of ddGroupSiftingUp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts down a variable until it reaches position xHigh.]
+
+ Description [Sifts down a variable until it reaches position xHigh.
+ Assumes that x is the bottom of a group (or a singleton). Records
+ all the moves. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddGroupSiftingDown(
+ DdManager * table,
+ int x,
+ int xHigh,
+ int (*checkFunction)(DdManager *, int, int),
+ Move ** moves)
+{
+ Move *move;
+ int y;
+ int size;
+ int limitSize;
+ int gxtop,gybot;
+ int R; /* upper bound on node decrease */
+ int xindex, yindex;
+ int isolated, allVars;
+ int z;
+ int zindex;
+#ifdef DD_DEBUG
+ int checkR;
+#endif
+
+ /* If the group consists of simple variables, there is no point in
+ ** sifting it down. This check is redundant if the projection functions
+ ** do not have external references, because the computation of the
+ ** lower bound takes care of the problem. It is necessary otherwise to
+ ** prevent the sifting down of simple variables. */
+ y = x;
+ allVars = 1;
+ do {
+ if (table->subtables[y].keys != 1) {
+ allVars = 0;
+ break;
+ }
+ y = table->subtables[y].next;
+ } while (table->subtables[y].next != (unsigned) x);
+ if (allVars)
+ return(1);
+
+ /* Initialize R. */
+ xindex = table->invperm[x];
+ gxtop = table->subtables[x].next;
+ limitSize = size = table->keys - table->isolated;
+ R = 0;
+ for (z = xHigh; z > gxtop; z--) {
+ zindex = table->invperm[z];
+ if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ R += table->subtables[z].keys - isolated;
+ }
+ }
+
+ originalLevel = x; /* for lazy sifting */
+
+ y = cuddNextHigh(table,x);
+ while (y <= xHigh && size - R < limitSize) {
+#ifdef DD_DEBUG
+ gxtop = table->subtables[x].next;
+ checkR = 0;
+ for (z = xHigh; z > gxtop; z--) {
+ zindex = table->invperm[z];
+ if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ checkR += table->subtables[z].keys - isolated;
+ }
+ }
+ assert(R >= checkR);
+#endif
+ /* Find bottom of y group. */
+ gybot = table->subtables[y].next;
+ while (table->subtables[gybot].next != (unsigned) y)
+ gybot = table->subtables[gybot].next;
+
+ if (checkFunction(table,x,y)) {
+ /* Group found: attach groups and record move. */
+ gxtop = table->subtables[x].next;
+ table->subtables[x].next = y;
+ table->subtables[gybot].next = gxtop;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddGroupSiftingDownOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->flags = MTR_NEWNODE;
+ move->size = table->keys - table->isolated;
+ move->next = *moves;
+ *moves = move;
+ } else if (table->subtables[x].next == (unsigned) x &&
+ table->subtables[y].next == (unsigned) y) {
+ /* x and y are self groups */
+ /* Update upper bound on node decrease. */
+ yindex = table->invperm[y];
+ if (cuddTestInteract(table,xindex,yindex)) {
+ isolated = table->vars[yindex]->ref == 1;
+ R -= table->subtables[y].keys - isolated;
+ }
+ size = cuddSwapInPlace(table,x,y);
+#ifdef DD_DEBUG
+ assert(table->subtables[x].next == (unsigned) x);
+ assert(table->subtables[y].next == (unsigned) y);
+#endif
+ if (size == 0) goto ddGroupSiftingDownOutOfMem;
+
+ /* Record move. */
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddGroupSiftingDownOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->flags = MTR_DEFAULT;
+ move->size = size;
+ move->next = *moves;
+ *moves = move;
+
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,
+ "ddGroupSiftingDown (2 single groups):\n");
+#endif
+ if ((double) size > (double) limitSize * table->maxGrowth)
+ return(1);
+ if (size < limitSize) limitSize = size;
+
+ x = y;
+ y = cuddNextHigh(table,x);
+ } else { /* Group move */
+ /* Update upper bound on node decrease: first phase. */
+ gxtop = table->subtables[x].next;
+ z = gxtop + 1;
+ do {
+ zindex = table->invperm[z];
+ if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ R -= table->subtables[z].keys - isolated;
+ }
+ z++;
+ } while (z <= gybot);
+ size = ddGroupMove(table,x,y,moves);
+ if (size == 0) goto ddGroupSiftingDownOutOfMem;
+ if ((double) size > (double) limitSize * table->maxGrowth)
+ return(1);
+ if (size < limitSize) limitSize = size;
+
+ /* Update upper bound on node decrease: second phase. */
+ gxtop = table->subtables[gybot].next;
+ for (z = gxtop + 1; z <= gybot; z++) {
+ zindex = table->invperm[z];
+ if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ R += table->subtables[z].keys - isolated;
+ }
+ }
+ }
+ x = gybot;
+ y = cuddNextHigh(table,x);
+ }
+
+ return(1);
+
+ddGroupSiftingDownOutOfMem:
+ while (*moves != NULL) {
+ move = (*moves)->next;
+ cuddDeallocNode(table, (DdNode *) *moves);
+ *moves = move;
+ }
+
+ return(0);
+
+} /* end of ddGroupSiftingDown */
+
+
+/**Function********************************************************************
+
+ Synopsis [Swaps two groups and records the move.]
+
+ Description [Swaps two groups and records the move. Returns the
+ number of keys in the DD table in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddGroupMove(
+ DdManager * table,
+ int x,
+ int y,
+ Move ** moves)
+{
+ Move *move;
+ int size;
+ int i,j,xtop,xbot,xsize,ytop,ybot,ysize,newxtop;
+ int swapx,swapy;
+#if defined(DD_DEBUG) && defined(DD_VERBOSE)
+ int initialSize,bestSize;
+#endif
+
+#if DD_DEBUG
+ /* We assume that x < y */
+ assert(x < y);
+#endif
+ /* Find top, bottom, and size for the two groups. */
+ xbot = x;
+ xtop = table->subtables[x].next;
+ xsize = xbot - xtop + 1;
+ ybot = y;
+ while ((unsigned) ybot < table->subtables[ybot].next)
+ ybot = table->subtables[ybot].next;
+ ytop = y;
+ ysize = ybot - ytop + 1;
+
+#if defined(DD_DEBUG) && defined(DD_VERBOSE)
+ initialSize = bestSize = table->keys - table->isolated;
+#endif
+ /* Sift the variables of the second group up through the first group */
+ for (i = 1; i <= ysize; i++) {
+ for (j = 1; j <= xsize; j++) {
+ size = cuddSwapInPlace(table,x,y);
+ if (size == 0) goto ddGroupMoveOutOfMem;
+#if defined(DD_DEBUG) && defined(DD_VERBOSE)
+ if (size < bestSize)
+ bestSize = size;
+#endif
+ swapx = x; swapy = y;
+ y = x;
+ x = cuddNextLow(table,y);
+ }
+ y = ytop + i;
+ x = cuddNextLow(table,y);
+ }
+#if defined(DD_DEBUG) && defined(DD_VERBOSE)
+ if ((bestSize < initialSize) && (bestSize < size))
+ (void) fprintf(table->out,"Missed local minimum: initialSize:%d bestSize:%d finalSize:%d\n",initialSize,bestSize,size);
+#endif
+
+ /* fix groups */
+ y = xtop; /* ytop is now where xtop used to be */
+ for (i = 0; i < ysize - 1; i++) {
+ table->subtables[y].next = cuddNextHigh(table,y);
+ y = cuddNextHigh(table,y);
+ }
+ table->subtables[y].next = xtop; /* y is bottom of its group, join */
+ /* it to top of its group */
+ x = cuddNextHigh(table,y);
+ newxtop = x;
+ for (i = 0; i < xsize - 1; i++) {
+ table->subtables[x].next = cuddNextHigh(table,x);
+ x = cuddNextHigh(table,x);
+ }
+ table->subtables[x].next = newxtop; /* x is bottom of its group, join */
+ /* it to top of its group */
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,"ddGroupMove:\n");
+#endif
+
+ /* Store group move */
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddGroupMoveOutOfMem;
+ move->x = swapx;
+ move->y = swapy;
+ move->flags = MTR_DEFAULT;
+ move->size = table->keys - table->isolated;
+ move->next = *moves;
+ *moves = move;
+
+ return(table->keys - table->isolated);
+
+ddGroupMoveOutOfMem:
+ while (*moves != NULL) {
+ move = (*moves)->next;
+ cuddDeallocNode(table, (DdNode *) *moves);
+ *moves = move;
+ }
+ return(0);
+
+} /* end of ddGroupMove */
+
+
+/**Function********************************************************************
+
+ Synopsis [Undoes the swap two groups.]
+
+ Description [Undoes the swap two groups. Returns 1 in case of
+ success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddGroupMoveBackward(
+ DdManager * table,
+ int x,
+ int y)
+{
+ int size;
+ int i,j,xtop,xbot,xsize,ytop,ybot,ysize,newxtop;
+
+
+#if DD_DEBUG
+ /* We assume that x < y */
+ assert(x < y);
+#endif
+
+ /* Find top, bottom, and size for the two groups. */
+ xbot = x;
+ xtop = table->subtables[x].next;
+ xsize = xbot - xtop + 1;
+ ybot = y;
+ while ((unsigned) ybot < table->subtables[ybot].next)
+ ybot = table->subtables[ybot].next;
+ ytop = y;
+ ysize = ybot - ytop + 1;
+
+ /* Sift the variables of the second group up through the first group */
+ for (i = 1; i <= ysize; i++) {
+ for (j = 1; j <= xsize; j++) {
+ size = cuddSwapInPlace(table,x,y);
+ if (size == 0)
+ return(0);
+ y = x;
+ x = cuddNextLow(table,y);
+ }
+ y = ytop + i;
+ x = cuddNextLow(table,y);
+ }
+
+ /* fix groups */
+ y = xtop;
+ for (i = 0; i < ysize - 1; i++) {
+ table->subtables[y].next = cuddNextHigh(table,y);
+ y = cuddNextHigh(table,y);
+ }
+ table->subtables[y].next = xtop; /* y is bottom of its group, join */
+ /* to its top */
+ x = cuddNextHigh(table,y);
+ newxtop = x;
+ for (i = 0; i < xsize - 1; i++) {
+ table->subtables[x].next = cuddNextHigh(table,x);
+ x = cuddNextHigh(table,x);
+ }
+ table->subtables[x].next = newxtop; /* x is bottom of its group, join */
+ /* to its top */
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,"ddGroupMoveBackward:\n");
+#endif
+
+ return(1);
+
+} /* end of ddGroupMoveBackward */
+
+
+/**Function********************************************************************
+
+ Synopsis [Determines the best position for a variables and returns
+ it there.]
+
+ Description [Determines the best position for a variables and returns
+ it there. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddGroupSiftingBackward(
+ DdManager * table,
+ Move * moves,
+ int size,
+ int upFlag,
+ int lazyFlag)
+{
+ Move *move;
+ int res;
+ Move *end_move;
+ int diff, tmp_diff;
+ int index, pairlev;
+
+ if (lazyFlag) {
+ end_move = NULL;
+
+ /* Find the minimum size, and the earliest position at which it
+ ** was achieved. */
+ for (move = moves; move != NULL; move = move->next) {
+ if (move->size < size) {
+ size = move->size;
+ end_move = move;
+ } else if (move->size == size) {
+ if (end_move == NULL) end_move = move;
+ }
+ }
+
+ /* Find among the moves that give minimum size the one that
+ ** minimizes the distance from the corresponding variable. */
+ if (moves != NULL) {
+ diff = Cudd_ReadSize(table) + 1;
+ index = (upFlag == 1) ?
+ table->invperm[moves->x] : table->invperm[moves->y];
+ pairlev = table->perm[Cudd_bddReadPairIndex(table, index)];
+
+ for (move = moves; move != NULL; move = move->next) {
+ if (move->size == size) {
+ if (upFlag == 1) {
+ tmp_diff = (move->x > pairlev) ?
+ move->x - pairlev : pairlev - move->x;
+ } else {
+ tmp_diff = (move->y > pairlev) ?
+ move->y - pairlev : pairlev - move->y;
+ }
+ if (tmp_diff < diff) {
+ diff = tmp_diff;
+ end_move = move;
+ }
+ }
+ }
+ }
+ } else {
+ /* Find the minimum size. */
+ for (move = moves; move != NULL; move = move->next) {
+ if (move->size < size) {
+ size = move->size;
+ }
+ }
+ }
+
+ /* In case of lazy sifting, end_move identifies the position at
+ ** which we want to stop. Otherwise, we stop as soon as we meet
+ ** the minimum size. */
+ for (move = moves; move != NULL; move = move->next) {
+ if (lazyFlag) {
+ if (move == end_move) return(1);
+ } else {
+ if (move->size == size) return(1);
+ }
+ if ((table->subtables[move->x].next == move->x) &&
+ (table->subtables[move->y].next == move->y)) {
+ res = cuddSwapInPlace(table,(int)move->x,(int)move->y);
+ if (!res) return(0);
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,"ddGroupSiftingBackward:\n");
+ assert(table->subtables[move->x].next == move->x);
+ assert(table->subtables[move->y].next == move->y);
+#endif
+ } else { /* Group move necessary */
+ if (move->flags == MTR_NEWNODE) {
+ ddDissolveGroup(table,(int)move->x,(int)move->y);
+ } else {
+ res = ddGroupMoveBackward(table,(int)move->x,(int)move->y);
+ if (!res) return(0);
+ }
+ }
+
+ }
+
+ return(1);
+
+} /* end of ddGroupSiftingBackward */
+
+
+/**Function********************************************************************
+
+ Synopsis [Merges groups in the DD table.]
+
+ Description [Creates a single group from low to high and adjusts the
+ index field of the tree node.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static void
+ddMergeGroups(
+ DdManager * table,
+ MtrNode * treenode,
+ int low,
+ int high)
+{
+ int i;
+ MtrNode *auxnode;
+ int saveindex;
+ int newindex;
+
+ /* Merge all variables from low to high in one group, unless
+ ** this is the topmost group. In such a case we do not merge lest
+ ** we lose the symmetry information. */
+ if (treenode != table->tree) {
+ for (i = low; i < high; i++)
+ table->subtables[i].next = i+1;
+ table->subtables[high].next = low;
+ }
+
+ /* Adjust the index fields of the tree nodes. If a node is the
+ ** first child of its parent, then the parent may also need adjustment. */
+ saveindex = treenode->index;
+ newindex = table->invperm[low];
+ auxnode = treenode;
+ do {
+ auxnode->index = newindex;
+ if (auxnode->parent == NULL ||
+ (int) auxnode->parent->index != saveindex)
+ break;
+ auxnode = auxnode->parent;
+ } while (1);
+ return;
+
+} /* end of ddMergeGroups */
+
+
+/**Function********************************************************************
+
+ Synopsis [Dissolves a group in the DD table.]
+
+ Description [x and y are variables in a group to be cut in two. The cut
+ is to pass between x and y.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static void
+ddDissolveGroup(
+ DdManager * table,
+ int x,
+ int y)
+{
+ int topx;
+ int boty;
+
+ /* find top and bottom of the two groups */
+ boty = y;
+ while ((unsigned) boty < table->subtables[boty].next)
+ boty = table->subtables[boty].next;
+
+ topx = table->subtables[boty].next;
+
+ table->subtables[boty].next = y;
+ table->subtables[x].next = topx;
+
+ return;
+
+} /* end of ddDissolveGroup */
+
+
+/**Function********************************************************************
+
+ Synopsis [Pretends to check two variables for aggregation.]
+
+ Description [Pretends to check two variables for aggregation. Always
+ returns 0.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddNoCheck(
+ DdManager * table,
+ int x,
+ int y)
+{
+ return(0);
+
+} /* end of ddNoCheck */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks two variables for aggregation.]
+
+ Description [Checks two variables for aggregation. The check is based
+ on the second difference of the number of nodes as a function of the
+ layer. If the second difference is lower than a given threshold
+ (typically negative) then the two variables should be aggregated.
+ Returns 1 if the two variables pass the test; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddSecDiffCheck(
+ DdManager * table,
+ int x,
+ int y)
+{
+ double Nx,Nx_1;
+ double Sx;
+ double threshold;
+ int xindex,yindex;
+
+ if (x==0) return(0);
+
+#ifdef DD_STATS
+ secdiffcalls++;
+#endif
+ Nx = (double) table->subtables[x].keys;
+ Nx_1 = (double) table->subtables[x-1].keys;
+ Sx = (table->subtables[y].keys/Nx) - (Nx/Nx_1);
+
+ threshold = table->recomb / 100.0;
+ if (Sx < threshold) {
+ xindex = table->invperm[x];
+ yindex = table->invperm[y];
+ if (cuddTestInteract(table,xindex,yindex)) {
+#if defined(DD_DEBUG) && defined(DD_VERBOSE)
+ (void) fprintf(table->out,
+ "Second difference for %d = %g Pos(%d)\n",
+ table->invperm[x],Sx,x);
+#endif
+#ifdef DD_STATS
+ secdiff++;
+#endif
+ return(1);
+ } else {
+#ifdef DD_STATS
+ secdiffmisfire++;
+#endif
+ return(0);
+ }
+
+ }
+ return(0);
+
+} /* end of ddSecDiffCheck */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks for extended symmetry of x and y.]
+
+ Description [Checks for extended symmetry of x and y. Returns 1 in
+ case of extended symmetry; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddExtSymmCheck(
+ DdManager * table,
+ int x,
+ int y)
+{
+ DdNode *f,*f0,*f1,*f01,*f00,*f11,*f10;
+ DdNode *one;
+ int comple; /* f0 is complemented */
+ int notproj; /* f is not a projection function */
+ int arccount; /* number of arcs from layer x to layer y */
+ int TotalRefCount; /* total reference count of layer y minus 1 */
+ int counter; /* number of nodes of layer x that are allowed */
+ /* to violate extended symmetry conditions */
+ int arccounter; /* number of arcs into layer y that are allowed */
+ /* to come from layers other than x */
+ int i;
+ int xindex;
+ int yindex;
+ int res;
+ int slots;
+ DdNodePtr *list;
+ DdNode *sentinel = &(table->sentinel);
+
+ xindex = table->invperm[x];
+ yindex = table->invperm[y];
+
+ /* If the two variables do not interact, we do not want to merge them. */
+ if (!cuddTestInteract(table,xindex,yindex))
+ return(0);
+
+#ifdef DD_DEBUG
+ /* Checks that x and y do not contain just the projection functions.
+ ** With the test on interaction, these test become redundant,
+ ** because an isolated projection function does not interact with
+ ** any other variable.
+ */
+ if (table->subtables[x].keys == 1) {
+ assert(table->vars[xindex]->ref != 1);
+ }
+ if (table->subtables[y].keys == 1) {
+ assert(table->vars[yindex]->ref != 1);
+ }
+#endif
+
+#ifdef DD_STATS
+ extsymmcalls++;
+#endif
+
+ arccount = 0;
+ counter = (int) (table->subtables[x].keys *
+ (table->symmviolation/100.0) + 0.5);
+ one = DD_ONE(table);
+
+ slots = table->subtables[x].slots;
+ list = table->subtables[x].nodelist;
+ for (i = 0; i < slots; i++) {
+ f = list[i];
+ while (f != sentinel) {
+ /* Find f1, f0, f11, f10, f01, f00. */
+ f1 = cuddT(f);
+ f0 = Cudd_Regular(cuddE(f));
+ comple = Cudd_IsComplement(cuddE(f));
+ notproj = f1 != one || f0 != one || f->ref != (DdHalfWord) 1;
+ if (f1->index == yindex) {
+ arccount++;
+ f11 = cuddT(f1); f10 = cuddE(f1);
+ } else {
+ if ((int) f0->index != yindex) {
+ /* If f is an isolated projection function it is
+ ** allowed to bypass layer y.
+ */
+ if (notproj) {
+ if (counter == 0)
+ return(0);
+ counter--; /* f bypasses layer y */
+ }
+ }
+ f11 = f10 = f1;
+ }
+ if ((int) f0->index == yindex) {
+ arccount++;
+ f01 = cuddT(f0); f00 = cuddE(f0);
+ } else {
+ f01 = f00 = f0;
+ }
+ if (comple) {
+ f01 = Cudd_Not(f01);
+ f00 = Cudd_Not(f00);
+ }
+
+ /* Unless we are looking at a projection function
+ ** without external references except the one from the
+ ** table, we insist that f01 == f10 or f11 == f00
+ */
+ if (notproj) {
+ if (f01 != f10 && f11 != f00) {
+ if (counter == 0)
+ return(0);
+ counter--;
+ }
+ }
+
+ f = f->next;
+ } /* while */
+ } /* for */
+
+ /* Calculate the total reference counts of y */
+ TotalRefCount = -1; /* -1 for projection function */
+ slots = table->subtables[y].slots;
+ list = table->subtables[y].nodelist;
+ for (i = 0; i < slots; i++) {
+ f = list[i];
+ while (f != sentinel) {
+ TotalRefCount += f->ref;
+ f = f->next;
+ }
+ }
+
+ arccounter = (int) (table->subtables[y].keys *
+ (table->arcviolation/100.0) + 0.5);
+ res = arccount >= TotalRefCount - arccounter;
+
+#if defined(DD_DEBUG) && defined(DD_VERBOSE)
+ if (res) {
+ (void) fprintf(table->out,
+ "Found extended symmetry! x = %d\ty = %d\tPos(%d,%d)\n",
+ xindex,yindex,x,y);
+ }
+#endif
+
+#ifdef DD_STATS
+ if (res)
+ extsymm++;
+#endif
+ return(res);
+
+} /* end ddExtSymmCheck */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks for grouping of x and y.]
+
+ Description [Checks for grouping of x and y. Returns 1 in
+ case of grouping; 0 otherwise. This function is used for lazy sifting.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddVarGroupCheck(
+ DdManager * table,
+ int x,
+ int y)
+{
+ int xindex = table->invperm[x];
+ int yindex = table->invperm[y];
+
+ if (Cudd_bddIsVarToBeUngrouped(table, xindex)) return(0);
+
+ if (Cudd_bddReadPairIndex(table, xindex) == yindex) {
+ if (ddIsVarHandled(table, xindex) ||
+ ddIsVarHandled(table, yindex)) {
+ if (Cudd_bddIsVarToBeGrouped(table, xindex) ||
+ Cudd_bddIsVarToBeGrouped(table, yindex) ) {
+ if (table->keys - table->isolated <= originalSize) {
+ return(1);
+ }
+ }
+ }
+ }
+
+ return(0);
+
+} /* end of ddVarGroupCheck */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sets a variable to already handled.]
+
+ Description [Sets a variable to already handled. This function is used
+ for lazy sifting.]
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+ddSetVarHandled(
+ DdManager *dd,
+ int index)
+{
+ if (index >= dd->size || index < 0) return(0);
+ dd->subtables[dd->perm[index]].varHandled = 1;
+ return(1);
+
+} /* end of ddSetVarHandled */
+
+
+/**Function********************************************************************
+
+ Synopsis [Resets a variable to be processed.]
+
+ Description [Resets a variable to be processed. This function is used
+ for lazy sifting.]
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+ddResetVarHandled(
+ DdManager *dd,
+ int index)
+{
+ if (index >= dd->size || index < 0) return(0);
+ dd->subtables[dd->perm[index]].varHandled = 0;
+ return(1);
+
+} /* end of ddResetVarHandled */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether a variables is already handled.]
+
+ Description [Checks whether a variables is already handled. This
+ function is used for lazy sifting.]
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+ddIsVarHandled(
+ DdManager *dd,
+ int index)
+{
+ if (index >= dd->size || index < 0) return(-1);
+ return dd->subtables[dd->perm[index]].varHandled;
+
+} /* end of ddIsVarHandled */
diff --git a/src/bdd/cudd/cuddHarwell.c b/src/bdd/cudd/cuddHarwell.c
new file mode 100644
index 00000000..10746186
--- /dev/null
+++ b/src/bdd/cudd/cuddHarwell.c
@@ -0,0 +1,541 @@
+/**CFile***********************************************************************
+
+ FileName [cuddHarwell.c]
+
+ PackageName [cudd]
+
+ Synopsis [Function to read a matrix in Harwell format.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_addHarwell()
+ </ul>
+ ]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddHarwell.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Reads in a matrix in the format of the Harwell-Boeing
+ benchmark suite.]
+
+ Description [Reads in a matrix in the format of the Harwell-Boeing
+ benchmark suite. The variables are ordered as follows:
+ <blockquote>
+ x\[0\] y\[0\] x\[1\] y\[1\] ...
+ </blockquote>
+ 0 is the most significant bit. On input, nx and ny hold the numbers
+ of row and column variables already in existence. On output, they
+ hold the numbers of row and column variables actually used by the
+ matrix. m and n are set to the numbers of rows and columns of the
+ matrix. Their values on input are immaterial. Returns 1 on
+ success; 0 otherwise. The ADD for the sparse matrix is returned in
+ E, and its reference count is > 0.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addRead Cudd_bddRead]
+
+******************************************************************************/
+int
+Cudd_addHarwell(
+ FILE * fp /* pointer to the input file */,
+ DdManager * dd /* DD manager */,
+ DdNode ** E /* characteristic function of the graph */,
+ DdNode *** x /* array of row variables */,
+ DdNode *** y /* array of column variables */,
+ DdNode *** xn /* array of complemented row variables */,
+ DdNode *** yn_ /* array of complemented column variables */,
+ int * nx /* number or row variables */,
+ int * ny /* number or column variables */,
+ int * m /* number of rows */,
+ int * n /* number of columns */,
+ int bx /* first index of row variables */,
+ int sx /* step of row variables */,
+ int by /* first index of column variables */,
+ int sy /* step of column variables */,
+ int pr /* verbosity level */)
+{
+ DdNode *one, *zero;
+ DdNode *w;
+ DdNode *cubex, *cubey, *minterm1;
+ int u, v, err, i, j, nv;
+ double val;
+ DdNode **lx, **ly, **lxn, **lyn; /* local copies of x, y, xn, yn_ */
+ int lnx, lny; /* local copies of nx and ny */
+ char title[73], key[9], mxtype[4], rhstyp[4];
+ int totcrd, ptrcrd, indcrd, valcrd, rhscrd,
+ nrow, ncol, nnzero, neltvl,
+ nrhs, nrhsix;
+ int *colptr, *rowind;
+#if 0
+ int nguess, nexact;
+ int *rhsptr, *rhsind;
+#endif
+
+ if (*nx < 0 || *ny < 0) return(0);
+
+ one = DD_ONE(dd);
+ zero = DD_ZERO(dd);
+
+ /* Read the header */
+ err = fscanf(fp, "%72c %8c", title, key);
+ if (err == EOF) {
+ return(0);
+ } else if (err != 2) {
+ return(0);
+ }
+ title[72] = (char) 0;
+ key[8] = (char) 0;
+
+ err = fscanf(fp, "%d %d %d %d %d", &totcrd, &ptrcrd, &indcrd,
+ &valcrd, &rhscrd);
+ if (err == EOF) {
+ return(0);
+ } else if (err != 5) {
+ return(0);
+ }
+
+ err = fscanf(fp, "%3s %d %d %d %d", mxtype, &nrow, &ncol,
+ &nnzero, &neltvl);
+ if (err == EOF) {
+ return(0);
+ } else if (err != 5) {
+ return(0);
+ }
+
+ /* Skip FORTRAN formats */
+ if (rhscrd == 0) {
+ err = fscanf(fp, "%*s %*s %*s \n");
+ } else {
+ err = fscanf(fp, "%*s %*s %*s %*s \n");
+ }
+ if (err == EOF) {
+ return(0);
+ } else if (err != 0) {
+ return(0);
+ }
+
+ /* Print out some stuff if requested to be verbose */
+ if (pr>0) {
+ (void) fprintf(dd->out,"%s: type %s, %d rows, %d columns, %d entries\n", key,
+ mxtype, nrow, ncol, nnzero);
+ if (pr>1) (void) fprintf(dd->out,"%s\n", title);
+ }
+
+ /* Check matrix type */
+ if (mxtype[0] != 'R' || mxtype[1] != 'U' || mxtype[2] != 'A') {
+ (void) fprintf(dd->err,"%s: Illegal matrix type: %s\n",
+ key, mxtype);
+ return(0);
+ }
+ if (neltvl != 0) return(0);
+
+ /* Read optional 5-th line */
+ if (rhscrd != 0) {
+ err = fscanf(fp, "%3c %d %d", rhstyp, &nrhs, &nrhsix);
+ if (err == EOF) {
+ return(0);
+ } else if (err != 3) {
+ return(0);
+ }
+ rhstyp[3] = (char) 0;
+ if (rhstyp[0] != 'F') {
+ (void) fprintf(dd->err,
+ "%s: Sparse right-hand side not yet supported\n", key);
+ return(0);
+ }
+ if (pr>0) (void) fprintf(dd->out,"%d right-hand side(s)\n", nrhs);
+ } else {
+ nrhs = 0;
+ }
+
+ /* Compute the number of variables */
+
+ /* row and column numbers start from 0 */
+ u = nrow - 1;
+ for (i=0; u > 0; i++) {
+ u >>= 1;
+ }
+ lnx = i;
+ if (nrhs == 0) {
+ v = ncol - 1;
+ } else {
+ v = 2* (ddMax(ncol, nrhs) - 1);
+ }
+ for (i=0; v > 0; i++) {
+ v >>= 1;
+ }
+ lny = i;
+
+ /* Allocate or reallocate arrays for variables as needed */
+ if (*nx == 0) {
+ if (lnx > 0) {
+ *x = lx = ALLOC(DdNode *,lnx);
+ if (lx == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ *xn = lxn = ALLOC(DdNode *,lnx);
+ if (lxn == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ } else {
+ *x = *xn = NULL;
+ }
+ } else if (lnx > *nx) {
+ *x = lx = REALLOC(DdNode *, *x, lnx);
+ if (lx == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ *xn = lxn = REALLOC(DdNode *, *xn, lnx);
+ if (lxn == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ } else {
+ lx = *x;
+ lxn = *xn;
+ }
+ if (*ny == 0) {
+ if (lny >0) {
+ *y = ly = ALLOC(DdNode *,lny);
+ if (ly == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ *yn_ = lyn = ALLOC(DdNode *,lny);
+ if (lyn == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ } else {
+ *y = *yn_ = NULL;
+ }
+ } else if (lny > *ny) {
+ *y = ly = REALLOC(DdNode *, *y, lny);
+ if (ly == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ *yn_ = lyn = REALLOC(DdNode *, *yn_, lny);
+ if (lyn == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ } else {
+ ly = *y;
+ lyn = *yn_;
+ }
+
+ /* Create new variables as needed */
+ for (i= *nx,nv=bx+(*nx)*sx; i < lnx; i++,nv+=sx) {
+ do {
+ dd->reordered = 0;
+ lx[i] = cuddUniqueInter(dd, nv, one, zero);
+ } while (dd->reordered == 1);
+ if (lx[i] == NULL) return(0);
+ cuddRef(lx[i]);
+ do {
+ dd->reordered = 0;
+ lxn[i] = cuddUniqueInter(dd, nv, zero, one);
+ } while (dd->reordered == 1);
+ if (lxn[i] == NULL) return(0);
+ cuddRef(lxn[i]);
+ }
+ for (i= *ny,nv=by+(*ny)*sy; i < lny; i++,nv+=sy) {
+ do {
+ dd->reordered = 0;
+ ly[i] = cuddUniqueInter(dd, nv, one, zero);
+ } while (dd->reordered == 1);
+ if (ly[i] == NULL) return(0);
+ cuddRef(ly[i]);
+ do {
+ dd->reordered = 0;
+ lyn[i] = cuddUniqueInter(dd, nv, zero, one);
+ } while (dd->reordered == 1);
+ if (lyn[i] == NULL) return(0);
+ cuddRef(lyn[i]);
+ }
+
+ /* Update matrix parameters */
+ *nx = lnx;
+ *ny = lny;
+ *m = nrow;
+ if (nrhs == 0) {
+ *n = ncol;
+ } else {
+ *n = (1 << (lny - 1)) + nrhs;
+ }
+
+ /* Read structure data */
+ colptr = ALLOC(int, ncol+1);
+ if (colptr == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ rowind = ALLOC(int, nnzero);
+ if (rowind == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+
+ for (i=0; i<ncol+1; i++) {
+ err = fscanf(fp, " %d ", &u);
+ if (err == EOF){
+ FREE(colptr);
+ FREE(rowind);
+ return(0);
+ } else if (err != 1) {
+ FREE(colptr);
+ FREE(rowind);
+ return(0);
+ }
+ colptr[i] = u - 1;
+ }
+ if (colptr[0] != 0) {
+ (void) fprintf(dd->err,"%s: Unexpected colptr[0] (%d)\n",
+ key,colptr[0]);
+ FREE(colptr);
+ FREE(rowind);
+ return(0);
+ }
+ for (i=0; i<nnzero; i++) {
+ err = fscanf(fp, " %d ", &u);
+ if (err == EOF){
+ FREE(colptr);
+ FREE(rowind);
+ return(0);
+ } else if (err != 1) {
+ FREE(colptr);
+ FREE(rowind);
+ return(0);
+ }
+ rowind[i] = u - 1;
+ }
+
+ *E = zero; cuddRef(*E);
+
+ for (j=0; j<ncol; j++) {
+ v = j;
+ cubey = one; cuddRef(cubey);
+ for (nv = lny - 1; nv>=0; nv--) {
+ if (v & 1) {
+ w = Cudd_addApply(dd, Cudd_addTimes, cubey, ly[nv]);
+ } else {
+ w = Cudd_addApply(dd, Cudd_addTimes, cubey, lyn[nv]);
+ }
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, cubey);
+ FREE(colptr);
+ FREE(rowind);
+ return(0);
+ }
+ cuddRef(w);
+ Cudd_RecursiveDeref(dd, cubey);
+ cubey = w;
+ v >>= 1;
+ }
+ for (i=colptr[j]; i<colptr[j+1]; i++) {
+ u = rowind[i];
+ err = fscanf(fp, " %lf ", &val);
+ if (err == EOF || err != 1){
+ Cudd_RecursiveDeref(dd, cubey);
+ FREE(colptr);
+ FREE(rowind);
+ return(0);
+ }
+ /* Create new Constant node if necessary */
+ cubex = cuddUniqueConst(dd, (CUDD_VALUE_TYPE) val);
+ if (cubex == NULL) {
+ Cudd_RecursiveDeref(dd, cubey);
+ FREE(colptr);
+ FREE(rowind);
+ return(0);
+ }
+ cuddRef(cubex);
+
+ for (nv = lnx - 1; nv>=0; nv--) {
+ if (u & 1) {
+ w = Cudd_addApply(dd, Cudd_addTimes, cubex, lx[nv]);
+ } else {
+ w = Cudd_addApply(dd, Cudd_addTimes, cubex, lxn[nv]);
+ }
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, cubey);
+ Cudd_RecursiveDeref(dd, cubex);
+ FREE(colptr);
+ FREE(rowind);
+ return(0);
+ }
+ cuddRef(w);
+ Cudd_RecursiveDeref(dd, cubex);
+ cubex = w;
+ u >>= 1;
+ }
+ minterm1 = Cudd_addApply(dd, Cudd_addTimes, cubey, cubex);
+ if (minterm1 == NULL) {
+ Cudd_RecursiveDeref(dd, cubey);
+ Cudd_RecursiveDeref(dd, cubex);
+ FREE(colptr);
+ FREE(rowind);
+ return(0);
+ }
+ cuddRef(minterm1);
+ Cudd_RecursiveDeref(dd, cubex);
+ w = Cudd_addApply(dd, Cudd_addPlus, *E, minterm1);
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, cubey);
+ FREE(colptr);
+ FREE(rowind);
+ return(0);
+ }
+ cuddRef(w);
+ Cudd_RecursiveDeref(dd, minterm1);
+ Cudd_RecursiveDeref(dd, *E);
+ *E = w;
+ }
+ Cudd_RecursiveDeref(dd, cubey);
+ }
+ FREE(colptr);
+ FREE(rowind);
+
+ /* Read right-hand sides */
+ for (j=0; j<nrhs; j++) {
+ v = j + (1<< (lny-1));
+ cubey = one; cuddRef(cubey);
+ for (nv = lny - 1; nv>=0; nv--) {
+ if (v & 1) {
+ w = Cudd_addApply(dd, Cudd_addTimes, cubey, ly[nv]);
+ } else {
+ w = Cudd_addApply(dd, Cudd_addTimes, cubey, lyn[nv]);
+ }
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, cubey);
+ return(0);
+ }
+ cuddRef(w);
+ Cudd_RecursiveDeref(dd, cubey);
+ cubey = w;
+ v >>= 1;
+ }
+ for (i=0; i<nrow; i++) {
+ u = i;
+ err = fscanf(fp, " %lf ", &val);
+ if (err == EOF || err != 1){
+ Cudd_RecursiveDeref(dd, cubey);
+ return(0);
+ }
+ /* Create new Constant node if necessary */
+ if (val == (double) 0.0) continue;
+ cubex = cuddUniqueConst(dd, (CUDD_VALUE_TYPE) val);
+ if (cubex == NULL) {
+ Cudd_RecursiveDeref(dd, cubey);
+ return(0);
+ }
+ cuddRef(cubex);
+
+ for (nv = lnx - 1; nv>=0; nv--) {
+ if (u & 1) {
+ w = Cudd_addApply(dd, Cudd_addTimes, cubex, lx[nv]);
+ } else {
+ w = Cudd_addApply(dd, Cudd_addTimes, cubex, lxn[nv]);
+ }
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, cubey);
+ Cudd_RecursiveDeref(dd, cubex);
+ return(0);
+ }
+ cuddRef(w);
+ Cudd_RecursiveDeref(dd, cubex);
+ cubex = w;
+ u >>= 1;
+ }
+ minterm1 = Cudd_addApply(dd, Cudd_addTimes, cubey, cubex);
+ if (minterm1 == NULL) {
+ Cudd_RecursiveDeref(dd, cubey);
+ Cudd_RecursiveDeref(dd, cubex);
+ return(0);
+ }
+ cuddRef(minterm1);
+ Cudd_RecursiveDeref(dd, cubex);
+ w = Cudd_addApply(dd, Cudd_addPlus, *E, minterm1);
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, cubey);
+ return(0);
+ }
+ cuddRef(w);
+ Cudd_RecursiveDeref(dd, minterm1);
+ Cudd_RecursiveDeref(dd, *E);
+ *E = w;
+ }
+ Cudd_RecursiveDeref(dd, cubey);
+ }
+
+ return(1);
+
+} /* end of Cudd_addHarwell */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
diff --git a/src/bdd/cudd/cuddInit.c b/src/bdd/cudd/cuddInit.c
new file mode 100644
index 00000000..aec8d286
--- /dev/null
+++ b/src/bdd/cudd/cuddInit.c
@@ -0,0 +1,283 @@
+/**CFile***********************************************************************
+
+ FileName [cuddInit.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions to initialize and shut down the DD manager.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_Init()
+ <li> Cudd_Quit()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddZddInitUniv()
+ <li> cuddZddFreeUniv()
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#define CUDD_MAIN
+#include "cuddInt.h"
+#undef CUDD_MAIN
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddInit.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Creates a new DD manager.]
+
+ Description [Creates a new DD manager, initializes the table, the
+ basic constants and the projection functions. If maxMemory is 0,
+ Cudd_Init decides suitable values for the maximum size of the cache
+ and for the limit for fast unique table growth based on the available
+ memory. Returns a pointer to the manager if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Quit]
+
+******************************************************************************/
+DdManager *
+Cudd_Init(
+ unsigned int numVars /* initial number of BDD variables (i.e., subtables) */,
+ unsigned int numVarsZ /* initial number of ZDD variables (i.e., subtables) */,
+ unsigned int numSlots /* initial size of the unique tables */,
+ unsigned int cacheSize /* initial size of the cache */,
+ unsigned long maxMemory /* target maximum memory occupation */)
+{
+ DdManager *unique;
+ int i,result;
+ DdNode *one, *zero;
+ unsigned int maxCacheSize;
+ unsigned int looseUpTo;
+ extern void (*MMoutOfMemory)(long);
+ void (*saveHandler)(long);
+
+ if (maxMemory == 0) {
+ maxMemory = getSoftDataLimit();
+ }
+ looseUpTo = (unsigned int) ((maxMemory / sizeof(DdNode)) /
+ DD_MAX_LOOSE_FRACTION);
+ unique = cuddInitTable(numVars,numVarsZ,numSlots,looseUpTo);
+ unique->maxmem = (unsigned) maxMemory / 10 * 9;
+ if (unique == NULL) return(NULL);
+ maxCacheSize = (unsigned int) ((maxMemory / sizeof(DdCache)) /
+ DD_MAX_CACHE_FRACTION);
+ result = cuddInitCache(unique,cacheSize,maxCacheSize);
+ if (result == 0) return(NULL);
+
+ saveHandler = MMoutOfMemory;
+ MMoutOfMemory = Cudd_OutOfMem;
+ unique->stash = ALLOC(char,(maxMemory / DD_STASH_FRACTION) + 4);
+ MMoutOfMemory = saveHandler;
+ if (unique->stash == NULL) {
+ (void) fprintf(unique->err,"Unable to set aside memory\n");
+ }
+
+ /* Initialize constants. */
+ unique->one = cuddUniqueConst(unique,1.0);
+ if (unique->one == NULL) return(0);
+ cuddRef(unique->one);
+ unique->zero = cuddUniqueConst(unique,0.0);
+ if (unique->zero == NULL) return(0);
+ cuddRef(unique->zero);
+#ifdef HAVE_IEEE_754
+ if (DD_PLUS_INF_VAL != DD_PLUS_INF_VAL * 3 ||
+ DD_PLUS_INF_VAL != DD_PLUS_INF_VAL / 3) {
+ (void) fprintf(unique->err,"Warning: Crippled infinite values\n");
+ (void) fprintf(unique->err,"Recompile without -DHAVE_IEEE_754\n");
+ }
+#endif
+ unique->plusinfinity = cuddUniqueConst(unique,DD_PLUS_INF_VAL);
+ if (unique->plusinfinity == NULL) return(0);
+ cuddRef(unique->plusinfinity);
+ unique->minusinfinity = cuddUniqueConst(unique,DD_MINUS_INF_VAL);
+ if (unique->minusinfinity == NULL) return(0);
+ cuddRef(unique->minusinfinity);
+ unique->background = unique->zero;
+
+ /* The logical zero is different from the CUDD_VALUE_TYPE zero! */
+ one = unique->one;
+ zero = Cudd_Not(one);
+ /* Create the projection functions. */
+ unique->vars = ALLOC(DdNodePtr,unique->maxSize);
+ if (unique->vars == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < unique->size; i++) {
+ unique->vars[i] = cuddUniqueInter(unique,i,one,zero);
+ if (unique->vars[i] == NULL) return(0);
+ cuddRef(unique->vars[i]);
+ }
+
+ if (unique->sizeZ)
+ cuddZddInitUniv(unique);
+
+ unique->memused += sizeof(DdNode *) * unique->maxSize;
+
+ return(unique);
+
+} /* end of Cudd_Init */
+
+
+/**Function********************************************************************
+
+ Synopsis [Deletes resources associated with a DD manager.]
+
+ Description [Deletes resources associated with a DD manager and
+ resets the global statistical counters. (Otherwise, another manaqger
+ subsequently created would inherit the stats of this one.)]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Init]
+
+******************************************************************************/
+void
+Cudd_Quit(
+ DdManager * unique)
+{
+ if (unique->stash != NULL) FREE(unique->stash);
+ cuddFreeTable(unique);
+
+} /* end of Cudd_Quit */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Initializes the ZDD universe.]
+
+ Description [Initializes the ZDD universe. Returns 1 if successful; 0
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddZddFreeUniv]
+
+******************************************************************************/
+int
+cuddZddInitUniv(
+ DdManager * zdd)
+{
+ DdNode *p, *res;
+ int i;
+
+ zdd->univ = ALLOC(DdNodePtr, zdd->sizeZ);
+ if (zdd->univ == NULL) {
+ zdd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+
+ res = DD_ONE(zdd);
+ cuddRef(res);
+ for (i = zdd->sizeZ - 1; i >= 0; i--) {
+ unsigned int index = zdd->invpermZ[i];
+ p = res;
+ res = cuddUniqueInterZdd(zdd, index, p, p);
+ if (res == NULL) {
+ Cudd_RecursiveDerefZdd(zdd,p);
+ FREE(zdd->univ);
+ return(0);
+ }
+ cuddRef(res);
+ cuddDeref(p);
+ zdd->univ[i] = res;
+ }
+
+#ifdef DD_VERBOSE
+ cuddZddP(zdd, zdd->univ[0]);
+#endif
+
+ return(1);
+
+} /* end of cuddZddInitUniv */
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees the ZDD universe.]
+
+ Description [Frees the ZDD universe.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddZddInitUniv]
+
+******************************************************************************/
+void
+cuddZddFreeUniv(
+ DdManager * zdd)
+{
+ if (zdd->univ) {
+ Cudd_RecursiveDerefZdd(zdd, zdd->univ[0]);
+ FREE(zdd->univ);
+ }
+
+} /* end of cuddZddFreeUniv */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
diff --git a/src/bdd/cudd/cuddInt.h b/src/bdd/cudd/cuddInt.h
new file mode 100644
index 00000000..a5d0cf16
--- /dev/null
+++ b/src/bdd/cudd/cuddInt.h
@@ -0,0 +1,1133 @@
+/**CHeaderFile*****************************************************************
+
+ FileName [cuddInt.h]
+
+ PackageName [cudd]
+
+ Synopsis [Internal data structures of the CUDD package.]
+
+ Description []
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+ Revision [$Id: cuddInt.h,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $]
+
+******************************************************************************/
+
+#ifndef _CUDDINT
+#define _CUDDINT
+
+
+/*---------------------------------------------------------------------------*/
+/* Nested includes */
+/*---------------------------------------------------------------------------*/
+
+#ifdef DD_MIS
+#include "array.h"
+#include "list.h"
+#include "st.h"
+#include "espresso.h"
+#include "node.h"
+#ifdef SIS
+#include "graph.h"
+#include "astg.h"
+#endif
+#include "network.h"
+#endif
+
+#include <math.h>
+#include "cudd.h"
+#include "st.h"
+
+#if defined(__GNUC__)
+# define DD_INLINE __inline__
+# if (__GNUC__ >2 || __GNUC_MINOR__ >=7)
+# define DD_UNUSED __attribute__ ((__unused__))
+# else
+# define DD_UNUSED
+# endif
+#else
+# if defined(__cplusplus)
+# define DD_INLINE inline
+# else
+# define DD_INLINE
+# endif
+# define DD_UNUSED
+#endif
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define DD_MAXREF ((DdHalfWord) ~0)
+
+#define DD_DEFAULT_RESIZE 10 /* how many extra variables */
+ /* should be added when resizing */
+#define DD_MEM_CHUNK 1022
+
+/* These definitions work for CUDD_VALUE_TYPE == double */
+#define DD_ONE_VAL (1.0)
+#define DD_ZERO_VAL (0.0)
+#define DD_EPSILON (1.0e-12)
+
+/* The definitions of +/- infinity in terms of HUGE_VAL work on
+** the DECstations and on many other combinations of OS/compiler.
+*/
+#ifdef HAVE_IEEE_754
+# define DD_PLUS_INF_VAL (HUGE_VAL)
+#else
+# define DD_PLUS_INF_VAL (10e301)
+# define DD_CRI_HI_MARK (10e150)
+# define DD_CRI_LO_MARK (-(DD_CRI_HI_MARK))
+#endif
+#define DD_MINUS_INF_VAL (-(DD_PLUS_INF_VAL))
+
+#define DD_NON_CONSTANT ((DdNode *) 1) /* for Cudd_bddIteConstant */
+
+/* Unique table and cache management constants. */
+#define DD_MAX_SUBTABLE_DENSITY 4 /* tells when to resize a subtable */
+/* gc when this percent are dead (measured w.r.t. slots, not keys)
+** The first limit (LO) applies normally. The second limit applies when
+** the package believes more space for the unique table (i.e., more dead
+** nodes) would improve performance, and the unique table is not already
+** too large. The third limit applies when memory is low.
+*/
+#define DD_GC_FRAC_LO DD_MAX_SUBTABLE_DENSITY * 0.25
+#define DD_GC_FRAC_HI DD_MAX_SUBTABLE_DENSITY * 1.0
+#define DD_GC_FRAC_MIN 0.2
+#define DD_MIN_HIT 30 /* resize cache when hit ratio
+ above this percentage (default) */
+#define DD_MAX_LOOSE_FRACTION 5 /* 1 / (max fraction of memory used for
+ unique table in fast growth mode) */
+#define DD_MAX_CACHE_FRACTION 3 /* 1 / (max fraction of memory used for
+ computed table if resizing enabled) */
+#define DD_STASH_FRACTION 64 /* 1 / (fraction of memory set
+ aside for emergencies) */
+#define DD_MAX_CACHE_TO_SLOTS_RATIO 4 /* used to limit the cache size */
+
+/* Variable ordering default parameter values. */
+#define DD_SIFT_MAX_VAR 1000
+#define DD_SIFT_MAX_SWAPS 2000000
+#define DD_DEFAULT_RECOMB 0
+#define DD_MAX_REORDER_GROWTH 1.2
+#define DD_FIRST_REORDER 4004 /* 4 for the constants */
+#define DD_DYN_RATIO 2 /* when to dynamically reorder */
+
+/* Primes for cache hash functions. */
+#define DD_P1 12582917
+#define DD_P2 4256249
+#define DD_P3 741457
+#define DD_P4 1618033999
+
+/* Cache tags for 3-operand operators. These tags are stored in the
+** least significant bits of the cache operand pointers according to
+** the following scheme. The tag consists of two hex digits. Both digits
+** must be even, so that they do not interfere with complementation bits.
+** The least significant one is stored in Bits 3:1 of the f operand in the
+** cache entry. Bit 1 is always 1, so that we can differentiate
+** three-operand operations from one- and two-operand operations.
+** Therefore, the least significant digit is one of {2,6,a,e}. The most
+** significant digit occupies Bits 3:1 of the g operand in the cache
+** entry. It can by any even digit between 0 and e. This gives a total
+** of 5 bits for the tag proper, which means a maximum of 32 three-operand
+** operations. */
+#define DD_ADD_ITE_TAG 0x02
+#define DD_BDD_AND_ABSTRACT_TAG 0x06
+#define DD_BDD_XOR_EXIST_ABSTRACT_TAG 0x0a
+#define DD_BDD_ITE_TAG 0x0e
+#define DD_ADD_BDD_DO_INTERVAL_TAG 0x22
+#define DD_BDD_CLIPPING_AND_ABSTRACT_UP_TAG 0x26
+#define DD_BDD_CLIPPING_AND_ABSTRACT_DOWN_TAG 0x2a
+#define DD_BDD_COMPOSE_RECUR_TAG 0x2e
+#define DD_ADD_COMPOSE_RECUR_TAG 0x42
+#define DD_ADD_NON_SIM_COMPOSE_TAG 0x46
+#define DD_EQUIV_DC_TAG 0x4a
+#define DD_ZDD_ITE_TAG 0x4e
+#define DD_ADD_ITE_CONSTANT_TAG 0x62
+#define DD_ADD_EVAL_CONST_TAG 0x66
+#define DD_BDD_ITE_CONSTANT_TAG 0x6a
+#define DD_ADD_OUT_SUM_TAG 0x6e
+#define DD_BDD_LEQ_UNLESS_TAG 0x82
+#define DD_ADD_TRIANGLE_TAG 0x86
+
+/* Generator constants. */
+#define CUDD_GEN_CUBES 0
+#define CUDD_GEN_NODES 1
+#define CUDD_GEN_ZDD_PATHS 2
+#define CUDD_GEN_EMPTY 0
+#define CUDD_GEN_NONEMPTY 1
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+struct DdGen {
+ DdManager *manager;
+ int type;
+ int status;
+ union {
+ struct {
+ int *cube;
+ CUDD_VALUE_TYPE value;
+ } cubes;
+ struct {
+ st_table *visited;
+ st_generator *stGen;
+ } nodes;
+ } gen;
+ struct {
+ int sp;
+ DdNode **stack;
+ } stack;
+ DdNode *node;
+};
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/* Hooks in CUDD are functions that the application registers with the
+** manager so that they are called at appropriate times. The functions
+** are passed the manager as argument; they should return 1 if
+** successful and 0 otherwise.
+*/
+typedef struct DdHook { /* hook list element */
+ int (*f) ARGS((DdManager *, char *, void *)); /* function to be called */
+ struct DdHook *next; /* next element in the list */
+} DdHook;
+
+#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
+typedef long ptrint;
+typedef unsigned long ptruint;
+#else
+typedef int ptrint;
+typedef unsigned int ptruint;
+#endif
+
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+
+typedef DdNode *DdNodePtr;
+
+/* Generic local cache item. */
+typedef struct DdLocalCacheItem {
+ DdNode *value;
+#ifdef DD_CACHE_PROFILE
+ ptrint count;
+#endif
+ DdNode *key[1];
+} DdLocalCacheItem;
+
+/* Local cache. */
+typedef struct DdLocalCache {
+ DdLocalCacheItem *item;
+ unsigned int itemsize;
+ unsigned int keysize;
+ unsigned int slots;
+ int shift;
+ double lookUps;
+ double minHit;
+ double hits;
+ unsigned int maxslots;
+ DdManager *manager;
+ struct DdLocalCache *next;
+} DdLocalCache;
+
+/* Generic hash item. */
+typedef struct DdHashItem {
+ struct DdHashItem *next;
+ ptrint count;
+ DdNode *value;
+ DdNode *key[1];
+} DdHashItem;
+
+/* Local hash table */
+typedef struct DdHashTable {
+ unsigned int keysize;
+ unsigned int itemsize;
+ DdHashItem **bucket;
+ DdHashItem *nextFree;
+ DdHashItem **memoryList;
+ unsigned int numBuckets;
+ int shift;
+ unsigned int size;
+ unsigned int maxsize;
+ DdManager *manager;
+} DdHashTable;
+
+typedef struct DdCache {
+ DdNode *f,*g; /* DDs */
+ ptruint h; /* either operator or DD */
+ DdNode *data; /* already constructed DD */
+#ifdef DD_CACHE_PROFILE
+ ptrint count;
+#endif
+} DdCache;
+
+typedef struct DdSubtable { /* subtable for one index */
+ DdNode **nodelist; /* hash table */
+ int shift; /* shift for hash function */
+ unsigned int slots; /* size of the hash table */
+ unsigned int keys; /* number of nodes stored in this table */
+ unsigned int maxKeys; /* slots * DD_MAX_SUBTABLE_DENSITY */
+ unsigned int dead; /* number of dead nodes in this table */
+ unsigned int next; /* index of next variable in group */
+ int bindVar; /* flag to bind this variable to its level */
+ /* Fields for lazy sifting. */
+ Cudd_VariableType varType; /* variable type (ps, ns, pi) */
+ int pairIndex; /* corresponding variable index (ps <-> ns) */
+ int varHandled; /* flag: 1 means variable is already handled */
+ Cudd_LazyGroupType varToBeGrouped; /* tells what grouping to apply */
+} DdSubtable;
+
+struct DdManager { /* specialized DD symbol table */
+ /* Constants */
+ DdNode sentinel; /* for collision lists */
+ DdNode *one; /* constant 1 */
+ DdNode *zero; /* constant 0 */
+ DdNode *plusinfinity; /* plus infinity */
+ DdNode *minusinfinity; /* minus infinity */
+ DdNode *background; /* background value */
+ /* Computed Table */
+ DdCache *acache; /* address of allocated memory for cache */
+ DdCache *cache; /* the cache-based computed table */
+ unsigned int cacheSlots; /* total number of cache entries */
+ int cacheShift; /* shift value for cache hash function */
+ double cacheMisses; /* number of cache misses (since resizing) */
+ double cacheHits; /* number of cache hits (since resizing) */
+ double minHit; /* hit percentage above which to resize */
+ int cacheSlack; /* slots still available for resizing */
+ unsigned int maxCacheHard; /* hard limit for cache size */
+ /* Unique Table */
+ int size; /* number of unique subtables */
+ int sizeZ; /* for ZDD */
+ int maxSize; /* max number of subtables before resizing */
+ int maxSizeZ; /* for ZDD */
+ DdSubtable *subtables; /* array of unique subtables */
+ DdSubtable *subtableZ; /* for ZDD */
+ DdSubtable constants; /* unique subtable for the constants */
+ unsigned int slots; /* total number of hash buckets */
+ unsigned int keys; /* total number of BDD and ADD nodes */
+ unsigned int keysZ; /* total number of ZDD nodes */
+ unsigned int dead; /* total number of dead BDD and ADD nodes */
+ unsigned int deadZ; /* total number of dead ZDD nodes */
+ unsigned int maxLive; /* maximum number of live nodes */
+ unsigned int minDead; /* do not GC if fewer than these dead */
+ double gcFrac; /* gc when this fraction is dead */
+ int gcEnabled; /* gc is enabled */
+ unsigned int looseUpTo; /* slow growth beyond this limit */
+ /* (measured w.r.t. slots, not keys) */
+ unsigned int initSlots; /* initial size of a subtable */
+ DdNode **stack; /* stack for iterative procedures */
+ double allocated; /* number of nodes allocated */
+ /* (not during reordering) */
+ double reclaimed; /* number of nodes brought back from the dead */
+ int isolated; /* isolated projection functions */
+ int *perm; /* current variable perm. (index to level) */
+ int *permZ; /* for ZDD */
+ int *invperm; /* current inv. var. perm. (level to index) */
+ int *invpermZ; /* for ZDD */
+ DdNode **vars; /* projection functions */
+ int *map; /* variable map for fast swap */
+ DdNode **univ; /* ZDD 1 for each variable */
+ int linearSize; /* number of rows and columns of linear */
+ long *interact; /* interacting variable matrix */
+ long *linear; /* linear transform matrix */
+ /* Memory Management */
+ DdNode **memoryList; /* memory manager for symbol table */
+ DdNode *nextFree; /* list of free nodes */
+ char *stash; /* memory reserve */
+#ifndef DD_NO_DEATH_ROW
+ DdNode **deathRow; /* queue for dereferencing */
+ int deathRowDepth; /* number of slots in the queue */
+ int nextDead; /* index in the queue */
+ unsigned deadMask; /* mask for circular index update */
+#endif
+ /* General Parameters */
+ CUDD_VALUE_TYPE epsilon; /* tolerance on comparisons */
+ /* Dynamic Reordering Parameters */
+ int reordered; /* flag set at the end of reordering */
+ int reorderings; /* number of calls to Cudd_ReduceHeap */
+ int siftMaxVar; /* maximum number of vars sifted */
+ int siftMaxSwap; /* maximum number of swaps per sifting */
+ double maxGrowth; /* maximum growth during reordering */
+ double maxGrowthAlt; /* alternate maximum growth for reordering */
+ int reordCycle; /* how often to apply alternate threshold */
+ int autoDyn; /* automatic dynamic reordering flag (BDD) */
+ int autoDynZ; /* automatic dynamic reordering flag (ZDD) */
+ Cudd_ReorderingType autoMethod; /* default reordering method */
+ Cudd_ReorderingType autoMethodZ; /* default reordering method (ZDD) */
+ int realign; /* realign ZDD order after BDD reordering */
+ int realignZ; /* realign BDD order after ZDD reordering */
+ unsigned int nextDyn; /* reorder if this size is reached */
+ unsigned int countDead; /* if 0, count deads to trigger reordering */
+ MtrNode *tree; /* Variable group tree (BDD) */
+ MtrNode *treeZ; /* Variable group tree (ZDD) */
+ Cudd_AggregationType groupcheck; /* Used during group sifting */
+ int recomb; /* Used during group sifting */
+ int symmviolation; /* Used during group sifting */
+ int arcviolation; /* Used during group sifting */
+ int populationSize; /* population size for GA */
+ int numberXovers; /* number of crossovers for GA */
+ DdLocalCache *localCaches; /* local caches currently in existence */
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+ char *hooks; /* application-specific field (used by vis) */
+ DdHook *preGCHook; /* hooks to be called before GC */
+ DdHook *postGCHook; /* hooks to be called after GC */
+ DdHook *preReorderingHook; /* hooks to be called before reordering */
+ DdHook *postReorderingHook; /* hooks to be called after reordering */
+ FILE *out; /* stdout for this manager */
+ FILE *err; /* stderr for this manager */
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ Cudd_ErrorType errorCode; /* info on last error */
+ /* Statistical counters. */
+ long memused; /* total memory allocated for the manager */
+ long maxmem; /* target maximum memory */
+ long maxmemhard; /* hard limit for maximum memory */
+ int garbageCollections; /* number of garbage collections */
+ long GCTime; /* total time spent in garbage collection */
+ long reordTime; /* total time spent in reordering */
+ double totCachehits; /* total number of cache hits */
+ double totCacheMisses; /* total number of cache misses */
+ double cachecollisions; /* number of cache collisions */
+ double cacheinserts; /* number of cache insertions */
+ double cacheLastInserts; /* insertions at the last cache resizing */
+ double cachedeletions; /* number of deletions during garbage coll. */
+#ifdef DD_STATS
+ double nodesFreed; /* number of nodes returned to the free list */
+ double nodesDropped; /* number of nodes killed by dereferencing */
+#endif
+ unsigned int peakLiveNodes; /* maximum number of live nodes */
+#ifdef DD_UNIQUE_PROFILE
+ double uniqueLookUps; /* number of unique table lookups */
+ double uniqueLinks; /* total distance traveled in coll. chains */
+#endif
+#ifdef DD_COUNT
+ double recursiveCalls; /* number of recursive calls */
+#ifdef DD_STATS
+ double nextSample; /* when to write next line of stats */
+#endif
+ double swapSteps; /* number of elementary reordering steps */
+#endif
+#ifdef DD_MIS
+ /* mis/verif compatibility fields */
+ array_t *iton; /* maps ids in ddNode to node_t */
+ array_t *order; /* copy of order_list */
+ lsHandle handle; /* where it is in network BDD list */
+ network_t *network;
+ st_table *local_order; /* for local BDDs */
+ int nvars; /* variables used so far */
+ int threshold; /* for pseudo var threshold value*/
+#endif
+};
+
+typedef struct Move {
+ DdHalfWord x;
+ DdHalfWord y;
+ unsigned int flags;
+ int size;
+ struct Move *next;
+} Move;
+
+/* Generic level queue item. */
+typedef struct DdQueueItem {
+ struct DdQueueItem *next;
+ struct DdQueueItem *cnext;
+ void *key;
+} DdQueueItem;
+
+/* Level queue. */
+typedef struct DdLevelQueue {
+ void *first;
+ DdQueueItem **last;
+ DdQueueItem *freelist;
+ DdQueueItem **buckets;
+ int levels;
+ int itemsize;
+ int size;
+ int maxsize;
+ int numBuckets;
+ int shift;
+} DdLevelQueue;
+
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**Macro***********************************************************************
+
+ Synopsis [Adds node to the head of the free list.]
+
+ Description [Adds node to the head of the free list. Does not
+ deallocate memory chunks that become free. This function is also
+ used by the dynamic reordering functions.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddAllocNode cuddDynamicAllocNode]
+
+******************************************************************************/
+#define cuddDeallocNode(unique,node) \
+ (node)->next = (unique)->nextFree; \
+ (unique)->nextFree = node;
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Increases the reference count of a node, if it is not
+ saturated.]
+
+ Description [Increases the reference count of a node, if it is not
+ saturated. This being a macro, it is faster than Cudd_Ref, but it
+ cannot be used in constructs like cuddRef(a = b()).]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_Ref]
+
+******************************************************************************/
+#define cuddRef(n) cuddSatInc(Cudd_Regular(n)->ref)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Decreases the reference count of a node, if it is not
+ saturated.]
+
+ Description [Decreases the reference count of node. It is primarily
+ used in recursive procedures to decrease the ref count of a result
+ node before returning it. This accomplishes the goal of removing the
+ protection applied by a previous cuddRef. This being a macro, it is
+ faster than Cudd_Deref, but it cannot be used in constructs like
+ cuddDeref(a = b()).]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_Deref]
+
+******************************************************************************/
+#define cuddDeref(n) cuddSatDec(Cudd_Regular(n)->ref)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns 1 if the node is a constant node.]
+
+ Description [Returns 1 if the node is a constant node (rather than an
+ internal node). All constant nodes have the same index
+ (CUDD_CONST_INDEX). The pointer passed to cuddIsConstant must be regular.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_IsConstant]
+
+******************************************************************************/
+#define cuddIsConstant(node) ((node)->index == CUDD_CONST_INDEX)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns the then child of an internal node.]
+
+ Description [Returns the then child of an internal node. If
+ <code>node</code> is a constant node, the result is unpredictable.
+ The pointer passed to cuddT must be regular.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_T]
+
+******************************************************************************/
+#define cuddT(node) ((node)->type.kids.T)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns the else child of an internal node.]
+
+ Description [Returns the else child of an internal node. If
+ <code>node</code> is a constant node, the result is unpredictable.
+ The pointer passed to cuddE must be regular.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_E]
+
+******************************************************************************/
+#define cuddE(node) ((node)->type.kids.E)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns the value of a constant node.]
+
+ Description [Returns the value of a constant node. If
+ <code>node</code> is an internal node, the result is unpredictable.
+ The pointer passed to cuddV must be regular.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_V]
+
+******************************************************************************/
+#define cuddV(node) ((node)->type.value)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Finds the current position of variable index in the
+ order.]
+
+ Description [Finds the current position of variable index in the
+ order. This macro duplicates the functionality of Cudd_ReadPerm,
+ but it does not check for out-of-bounds indices and it is more
+ efficient.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_ReadPerm]
+
+******************************************************************************/
+#define cuddI(dd,index) (((index)==CUDD_CONST_INDEX)?(int)(index):(dd)->perm[(index)])
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Finds the current position of ZDD variable index in the
+ order.]
+
+ Description [Finds the current position of ZDD variable index in the
+ order. This macro duplicates the functionality of Cudd_ReadPermZdd,
+ but it does not check for out-of-bounds indices and it is more
+ efficient.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_ReadPermZdd]
+
+******************************************************************************/
+#define cuddIZ(dd,index) (((index)==CUDD_CONST_INDEX)?(int)(index):(dd)->permZ[(index)])
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Hash function for the unique table.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso [ddCHash ddCHash2]
+
+******************************************************************************/
+#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
+#define ddHash(f,g,s) \
+((((unsigned)(unsigned long)(f) * DD_P1 + \
+ (unsigned)(unsigned long)(g)) * DD_P2) >> (s))
+#else
+#define ddHash(f,g,s) \
+((((unsigned)(f) * DD_P1 + (unsigned)(g)) * DD_P2) >> (s))
+#endif
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Hash function for the cache.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso [ddHash ddCHash2]
+
+******************************************************************************/
+#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
+#define ddCHash(o,f,g,h,s) \
+((((((unsigned)(unsigned long)(f) + (unsigned)(unsigned long)(o)) * DD_P1 + \
+ (unsigned)(unsigned long)(g)) * DD_P2 + \
+ (unsigned)(unsigned long)(h)) * DD_P3) >> (s))
+#else
+#define ddCHash(o,f,g,h,s) \
+((((((unsigned)(f) + (unsigned)(o)) * DD_P1 + (unsigned)(g)) * DD_P2 + \
+ (unsigned)(h)) * DD_P3) >> (s))
+#endif
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Hash function for the cache for functions with two
+ operands.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso [ddHash ddCHash]
+
+******************************************************************************/
+#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
+#define ddCHash2(o,f,g,s) \
+(((((unsigned)(unsigned long)(f) + (unsigned)(unsigned long)(o)) * DD_P1 + \
+ (unsigned)(unsigned long)(g)) * DD_P2) >> (s))
+#else
+#define ddCHash2(o,f,g,s) \
+(((((unsigned)(f) + (unsigned)(o)) * DD_P1 + (unsigned)(g)) * DD_P2) >> (s))
+#endif
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Clears the 4 least significant bits of a pointer.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+#define cuddClean(p) ((DdNode *)((ptruint)(p) & ~0xf))
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Computes the minimum of two numbers.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso [ddMax]
+
+******************************************************************************/
+#define ddMin(x,y) (((y) < (x)) ? (y) : (x))
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Computes the maximum of two numbers.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso [ddMin]
+
+******************************************************************************/
+#define ddMax(x,y) (((y) > (x)) ? (y) : (x))
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Computes the absolute value of a number.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+#define ddAbs(x) (((x)<0) ? -(x) : (x))
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns 1 if the absolute value of the difference of the two
+ arguments x and y is less than e.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+#define ddEqualVal(x,y,e) (ddAbs((x)-(y))<(e))
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Saturating increment operator.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso [cuddSatDec]
+
+******************************************************************************/
+#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
+#define cuddSatInc(x) ((x)++)
+#else
+#define cuddSatInc(x) ((x) += (x) != (DdHalfWord)DD_MAXREF)
+#endif
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Saturating decrement operator.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso [cuddSatInc]
+
+******************************************************************************/
+#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
+#define cuddSatDec(x) ((x)--)
+#else
+#define cuddSatDec(x) ((x) -= (x) != (DdHalfWord)DD_MAXREF)
+#endif
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns the constant 1 node.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso [DD_ZERO DD_PLUS_INFINITY DD_MINUS_INFINITY]
+
+******************************************************************************/
+#define DD_ONE(dd) ((dd)->one)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns the arithmetic 0 constant node.]
+
+ Description [Returns the arithmetic 0 constant node. This is different
+ from the logical zero. The latter is obtained by
+ Cudd_Not(DD_ONE(dd)).]
+
+ SideEffects [none]
+
+ SeeAlso [DD_ONE Cudd_Not DD_PLUS_INFINITY DD_MINUS_INFINITY]
+
+******************************************************************************/
+#define DD_ZERO(dd) ((dd)->zero)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns the plus infinity constant node.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso [DD_ONE DD_ZERO DD_MINUS_INFINITY]
+
+******************************************************************************/
+#define DD_PLUS_INFINITY(dd) ((dd)->plusinfinity)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Returns the minus infinity constant node.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso [DD_ONE DD_ZERO DD_PLUS_INFINITY]
+
+******************************************************************************/
+#define DD_MINUS_INFINITY(dd) ((dd)->minusinfinity)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Enforces DD_MINUS_INF_VAL <= x <= DD_PLUS_INF_VAL.]
+
+ Description [Enforces DD_MINUS_INF_VAL <= x <= DD_PLUS_INF_VAL.
+ Furthermore, if x <= DD_MINUS_INF_VAL/2, x is set to
+ DD_MINUS_INF_VAL. Similarly, if DD_PLUS_INF_VAL/2 <= x, x is set to
+ DD_PLUS_INF_VAL. Normally this macro is a NOOP. However, if
+ HAVE_IEEE_754 is not defined, it makes sure that a value does not
+ get larger than infinity in absolute value, and once it gets to
+ infinity, stays there. If the value overflows before this macro is
+ applied, no recovery is possible.]
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+#ifdef HAVE_IEEE_754
+#define cuddAdjust(x)
+#else
+#define cuddAdjust(x) ((x) = ((x) >= DD_CRI_HI_MARK) ? DD_PLUS_INF_VAL : (((x) <= DD_CRI_LO_MARK) ? DD_MINUS_INF_VAL : (x)))
+#endif
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Extract the least significant digit of a double digit.]
+
+ Description [Extract the least significant digit of a double digit. Used
+ in the manipulation of arbitrary precision integers.]
+
+ SideEffects [None]
+
+ SeeAlso [DD_MSDIGIT]
+
+******************************************************************************/
+#define DD_LSDIGIT(x) ((x) & DD_APA_MASK)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Extract the most significant digit of a double digit.]
+
+ Description [Extract the most significant digit of a double digit. Used
+ in the manipulation of arbitrary precision integers.]
+
+ SideEffects [None]
+
+ SeeAlso [DD_LSDIGIT]
+
+******************************************************************************/
+#define DD_MSDIGIT(x) ((x) >> DD_APA_BITS)
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Outputs a line of stats.]
+
+ Description [Outputs a line of stats if DD_COUNT and DD_STATS are
+ defined. Increments the number of recursive calls if DD_COUNT is
+ defined.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+#ifdef DD_COUNT
+#ifdef DD_STATS
+#define statLine(dd) dd->recursiveCalls++; \
+if (dd->recursiveCalls == dd->nextSample) {(void) fprintf(dd->err, \
+"@%.0f: %u nodes %u live %.0f dropped %.0f reclaimed\n", dd->recursiveCalls, \
+dd->keys, dd->keys - dd->dead, dd->nodesDropped, dd->reclaimed); \
+dd->nextSample += 250000;}
+#else
+#define statLine(dd) dd->recursiveCalls++;
+#endif
+#else
+#define statLine(dd)
+#endif
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Function prototypes */
+/*---------------------------------------------------------------------------*/
+
+EXTERN DdNode * cuddAddExistAbstractRecur ARGS((DdManager *manager, DdNode *f, DdNode *cube));
+EXTERN DdNode * cuddAddUnivAbstractRecur ARGS((DdManager *manager, DdNode *f, DdNode *cube));
+EXTERN DdNode * cuddAddOrAbstractRecur ARGS((DdManager *manager, DdNode *f, DdNode *cube));
+EXTERN DdNode * cuddAddApplyRecur ARGS((DdManager *dd, DdNode * (*)(DdManager *, DdNode **, DdNode **), DdNode *f, DdNode *g));
+EXTERN DdNode * cuddAddMonadicApplyRecur ARGS((DdManager * dd, DdNode * (*op)(DdManager *, DdNode *), DdNode * f));
+EXTERN DdNode * cuddAddScalarInverseRecur ARGS((DdManager *dd, DdNode *f, DdNode *epsilon));
+EXTERN DdNode * cuddAddIteRecur ARGS((DdManager *dd, DdNode *f, DdNode *g, DdNode *h));
+EXTERN DdNode * cuddAddCmplRecur ARGS((DdManager *dd, DdNode *f));
+EXTERN DdNode * cuddAddNegateRecur ARGS((DdManager *dd, DdNode *f));
+EXTERN DdNode * cuddAddRoundOffRecur ARGS((DdManager *dd, DdNode *f, double trunc));
+EXTERN DdNode * cuddUnderApprox ARGS((DdManager *dd, DdNode *f, int numVars, int threshold, int safe, double quality));
+EXTERN DdNode * cuddRemapUnderApprox ARGS((DdManager *dd, DdNode *f, int numVars, int threshold, double quality));
+EXTERN DdNode * cuddBiasedUnderApprox ARGS((DdManager *dd, DdNode *f, DdNode *b, int numVars, int threshold, double quality1, double quality0));
+EXTERN DdNode * cuddBddAndAbstractRecur ARGS((DdManager *manager, DdNode *f, DdNode *g, DdNode *cube));
+EXTERN int cuddAnnealing ARGS((DdManager *table, int lower, int upper));
+EXTERN DdNode * cuddBddExistAbstractRecur ARGS((DdManager *manager, DdNode *f, DdNode *cube));
+EXTERN DdNode * cuddBddXorExistAbstractRecur ARGS((DdManager *manager, DdNode *f, DdNode *g, DdNode *cube));
+EXTERN DdNode * cuddBddBooleanDiffRecur ARGS((DdManager *manager, DdNode *f, DdNode *var));
+EXTERN DdNode * cuddBddIteRecur ARGS((DdManager *dd, DdNode *f, DdNode *g, DdNode *h));
+EXTERN DdNode * cuddBddIntersectRecur ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * cuddBddAndRecur ARGS((DdManager *manager, DdNode *f, DdNode *g));
+EXTERN DdNode * cuddBddXorRecur ARGS((DdManager *manager, DdNode *f, DdNode *g));
+EXTERN DdNode * cuddBddTransfer ARGS((DdManager *ddS, DdManager *ddD, DdNode *f));
+EXTERN DdNode * cuddAddBddDoPattern ARGS((DdManager *dd, DdNode *f));
+EXTERN int cuddInitCache ARGS((DdManager *unique, unsigned int cacheSize, unsigned int maxCacheSize));
+EXTERN void cuddCacheInsert ARGS((DdManager *table, ptruint op, DdNode *f, DdNode *g, DdNode *h, DdNode *data));
+EXTERN void cuddCacheInsert2 ARGS((DdManager *table, DdNode * (*)(DdManager *, DdNode *, DdNode *), DdNode *f, DdNode *g, DdNode *data));
+EXTERN void cuddCacheInsert1 ARGS((DdManager *table, DdNode * (*)(DdManager *, DdNode *), DdNode *f, DdNode *data));
+EXTERN DdNode * cuddCacheLookup ARGS((DdManager *table, ptruint op, DdNode *f, DdNode *g, DdNode *h));
+EXTERN DdNode * cuddCacheLookupZdd ARGS((DdManager *table, ptruint op, DdNode *f, DdNode *g, DdNode *h));
+EXTERN DdNode * cuddCacheLookup2 ARGS((DdManager *table, DdNode * (*)(DdManager *, DdNode *, DdNode *), DdNode *f, DdNode *g));
+EXTERN DdNode * cuddCacheLookup1 ARGS((DdManager *table, DdNode * (*)(DdManager *, DdNode *), DdNode *f));
+EXTERN DdNode * cuddCacheLookup2Zdd ARGS((DdManager *table, DdNode * (*)(DdManager *, DdNode *, DdNode *), DdNode *f, DdNode *g));
+EXTERN DdNode * cuddCacheLookup1Zdd ARGS((DdManager *table, DdNode * (*)(DdManager *, DdNode *), DdNode *f));
+EXTERN DdNode * cuddConstantLookup ARGS((DdManager *table, ptruint op, DdNode *f, DdNode *g, DdNode *h));
+EXTERN int cuddCacheProfile ARGS((DdManager *table, FILE *fp));
+EXTERN void cuddCacheResize ARGS((DdManager *table));
+EXTERN void cuddCacheFlush ARGS((DdManager *table));
+EXTERN int cuddComputeFloorLog2 ARGS((unsigned int value));
+EXTERN int cuddHeapProfile ARGS((DdManager *dd));
+EXTERN void cuddPrintNode ARGS((DdNode *f, FILE *fp));
+EXTERN void cuddPrintVarGroups ARGS((DdManager * dd, MtrNode * root, int zdd, int silent));
+EXTERN DdNode * cuddBddClippingAnd ARGS((DdManager *dd, DdNode *f, DdNode *g, int maxDepth, int direction));
+EXTERN DdNode * cuddBddClippingAndAbstract ARGS((DdManager *dd, DdNode *f, DdNode *g, DdNode *cube, int maxDepth, int direction));
+EXTERN void cuddGetBranches ARGS((DdNode *g, DdNode **g1, DdNode **g0));
+EXTERN int cuddCheckCube ARGS((DdManager *dd, DdNode *g));
+EXTERN DdNode * cuddCofactorRecur ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * cuddBddComposeRecur ARGS((DdManager *dd, DdNode *f, DdNode *g, DdNode *proj));
+EXTERN DdNode * cuddAddComposeRecur ARGS((DdManager *dd, DdNode *f, DdNode *g, DdNode *proj));
+EXTERN int cuddExact ARGS((DdManager *table, int lower, int upper));
+EXTERN DdNode * cuddBddConstrainRecur ARGS((DdManager *dd, DdNode *f, DdNode *c));
+EXTERN DdNode * cuddBddRestrictRecur ARGS((DdManager *dd, DdNode *f, DdNode *c));
+EXTERN DdNode * cuddAddConstrainRecur ARGS((DdManager *dd, DdNode *f, DdNode *c));
+EXTERN DdNode * cuddAddRestrictRecur ARGS((DdManager *dd, DdNode *f, DdNode *c));
+EXTERN DdNode * cuddBddLICompaction ARGS((DdManager *dd, DdNode *f, DdNode *c));
+EXTERN int cuddGa ARGS((DdManager *table, int lower, int upper));
+EXTERN int cuddTreeSifting ARGS((DdManager *table, Cudd_ReorderingType method));
+EXTERN int cuddZddInitUniv ARGS((DdManager *zdd));
+EXTERN void cuddZddFreeUniv ARGS((DdManager *zdd));
+EXTERN void cuddSetInteract ARGS((DdManager *table, int x, int y));
+EXTERN int cuddTestInteract ARGS((DdManager *table, int x, int y));
+EXTERN int cuddInitInteract ARGS((DdManager *table));
+EXTERN DdLocalCache * cuddLocalCacheInit ARGS((DdManager *manager, unsigned int keySize, unsigned int cacheSize, unsigned int maxCacheSize));
+EXTERN void cuddLocalCacheQuit ARGS((DdLocalCache *cache));
+EXTERN void cuddLocalCacheInsert ARGS((DdLocalCache *cache, DdNodePtr *key, DdNode *value));
+EXTERN DdNode * cuddLocalCacheLookup ARGS((DdLocalCache *cache, DdNodePtr *key));
+EXTERN void cuddLocalCacheClearDead ARGS((DdManager *manager));
+EXTERN int cuddIsInDeathRow ARGS((DdManager *dd, DdNode *f));
+EXTERN int cuddTimesInDeathRow ARGS((DdManager *dd, DdNode *f));
+EXTERN void cuddLocalCacheClearAll ARGS((DdManager *manager));
+#ifdef DD_CACHE_PROFILE
+EXTERN int cuddLocalCacheProfile ARGS((DdLocalCache *cache));
+#endif
+EXTERN DdHashTable * cuddHashTableInit ARGS((DdManager *manager, unsigned int keySize, unsigned int initSize));
+EXTERN void cuddHashTableQuit ARGS((DdHashTable *hash));
+EXTERN int cuddHashTableInsert ARGS((DdHashTable *hash, DdNodePtr *key, DdNode *value, ptrint count));
+EXTERN DdNode * cuddHashTableLookup ARGS((DdHashTable *hash, DdNodePtr *key));
+EXTERN int cuddHashTableInsert1 ARGS((DdHashTable *hash, DdNode *f, DdNode *value, ptrint count));
+EXTERN DdNode * cuddHashTableLookup1 ARGS((DdHashTable *hash, DdNode *f));
+EXTERN int cuddHashTableInsert2 ARGS((DdHashTable *hash, DdNode *f, DdNode *g, DdNode *value, ptrint count));
+EXTERN DdNode * cuddHashTableLookup2 ARGS((DdHashTable *hash, DdNode *f, DdNode *g));
+EXTERN int cuddHashTableInsert3 ARGS((DdHashTable *hash, DdNode *f, DdNode *g, DdNode *h, DdNode *value, ptrint count));
+EXTERN DdNode * cuddHashTableLookup3 ARGS((DdHashTable *hash, DdNode *f, DdNode *g, DdNode *h));
+EXTERN DdLevelQueue * cuddLevelQueueInit ARGS((int levels, int itemSize, int numBuckets));
+EXTERN void cuddLevelQueueQuit ARGS((DdLevelQueue *queue));
+EXTERN void * cuddLevelQueueEnqueue ARGS((DdLevelQueue *queue, void *key, int level));
+EXTERN void cuddLevelQueueDequeue ARGS((DdLevelQueue *queue, int level));
+EXTERN int cuddLinearAndSifting ARGS((DdManager *table, int lower, int upper));
+EXTERN DdNode * cuddBddLiteralSetIntersectionRecur ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * cuddCProjectionRecur ARGS((DdManager *dd, DdNode *R, DdNode *Y, DdNode *Ysupp));
+EXTERN DdNode * cuddBddClosestCube ARGS((DdManager *dd, DdNode *f, DdNode *g, CUDD_VALUE_TYPE bound));
+EXTERN void cuddReclaim ARGS((DdManager *table, DdNode *n));
+EXTERN void cuddReclaimZdd ARGS((DdManager *table, DdNode *n));
+EXTERN void cuddClearDeathRow ARGS((DdManager *table));
+EXTERN void cuddShrinkDeathRow ARGS((DdManager *table));
+EXTERN DdNode * cuddDynamicAllocNode ARGS((DdManager *table));
+EXTERN int cuddSifting ARGS((DdManager *table, int lower, int upper));
+EXTERN int cuddSwapping ARGS((DdManager *table, int lower, int upper, Cudd_ReorderingType heuristic));
+EXTERN int cuddNextHigh ARGS((DdManager *table, int x));
+EXTERN int cuddNextLow ARGS((DdManager *table, int x));
+EXTERN int cuddSwapInPlace ARGS((DdManager *table, int x, int y));
+EXTERN int cuddBddAlignToZdd ARGS((DdManager *table));
+EXTERN DdNode * cuddBddMakePrime ARGS((DdManager *dd, DdNode *cube, DdNode *f));
+EXTERN DdNode * cuddSolveEqnRecur ARGS((DdManager *bdd, DdNode *F, DdNode *Y, DdNode **G, int n, int *yIndex, int i));
+EXTERN DdNode * cuddVerifySol ARGS((DdManager *bdd, DdNode *F, DdNode **G, int *yIndex, int n));
+#ifdef ST_INCLUDED
+EXTERN DdNode* cuddSplitSetRecur ARGS((DdManager *manager, st_table *mtable, int *varSeen, DdNode *p, double n, double max, int index));
+#endif
+EXTERN DdNode * cuddSubsetHeavyBranch ARGS((DdManager *dd, DdNode *f, int numVars, int threshold));
+EXTERN DdNode * cuddSubsetShortPaths ARGS((DdManager *dd, DdNode *f, int numVars, int threshold, int hardlimit));
+EXTERN int cuddSymmCheck ARGS((DdManager *table, int x, int y));
+EXTERN int cuddSymmSifting ARGS((DdManager *table, int lower, int upper));
+EXTERN int cuddSymmSiftingConv ARGS((DdManager *table, int lower, int upper));
+EXTERN DdNode * cuddAllocNode ARGS((DdManager *unique));
+EXTERN DdManager * cuddInitTable ARGS((unsigned int numVars, unsigned int numVarsZ, unsigned int numSlots, unsigned int looseUpTo));
+EXTERN void cuddFreeTable ARGS((DdManager *unique));
+EXTERN int cuddGarbageCollect ARGS((DdManager *unique, int clearCache));
+EXTERN int cuddGarbageCollectZdd ARGS((DdManager *unique, int clearCache));
+EXTERN DdNode * cuddZddGetNode ARGS((DdManager *zdd, int id, DdNode *T, DdNode *E));
+EXTERN DdNode * cuddZddGetNodeIVO ARGS((DdManager *dd, int index, DdNode *g, DdNode *h));
+EXTERN DdNode * cuddUniqueInter ARGS((DdManager *unique, int index, DdNode *T, DdNode *E));
+EXTERN DdNode * cuddUniqueInterIVO ARGS((DdManager *unique, int index, DdNode *T, DdNode *E));
+EXTERN DdNode * cuddUniqueInterZdd ARGS((DdManager *unique, int index, DdNode *T, DdNode *E));
+EXTERN DdNode * cuddUniqueConst ARGS((DdManager *unique, CUDD_VALUE_TYPE value));
+EXTERN void cuddRehash ARGS((DdManager *unique, int i));
+EXTERN void cuddShrinkSubtable ARGS((DdManager *unique, int i));
+EXTERN int cuddInsertSubtables ARGS((DdManager *unique, int n, int level));
+EXTERN int cuddDestroySubtables ARGS((DdManager *unique, int n));
+EXTERN int cuddResizeTableZdd ARGS((DdManager *unique, int index));
+EXTERN void cuddSlowTableGrowth ARGS((DdManager *unique));
+EXTERN int cuddP ARGS((DdManager *dd, DdNode *f));
+#ifdef ST_INCLUDED
+EXTERN enum st_retval cuddStCountfree ARGS((char *key, char *value, char *arg));
+EXTERN int cuddCollectNodes ARGS((DdNode *f, st_table *visited));
+#endif
+EXTERN int cuddWindowReorder ARGS((DdManager *table, int low, int high, Cudd_ReorderingType submethod));
+EXTERN DdNode * cuddZddProduct ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * cuddZddUnateProduct ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * cuddZddWeakDiv ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * cuddZddWeakDivF ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * cuddZddDivide ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN DdNode * cuddZddDivideF ARGS((DdManager *dd, DdNode *f, DdNode *g));
+EXTERN int cuddZddGetCofactors3 ARGS((DdManager *dd, DdNode *f, int v, DdNode **f1, DdNode **f0, DdNode **fd));
+EXTERN int cuddZddGetCofactors2 ARGS((DdManager *dd, DdNode *f, int v, DdNode **f1, DdNode **f0));
+EXTERN DdNode * cuddZddComplement ARGS((DdManager *dd, DdNode *node));
+EXTERN int cuddZddGetPosVarIndex(DdManager * dd, int index);
+EXTERN int cuddZddGetNegVarIndex(DdManager * dd, int index);
+EXTERN int cuddZddGetPosVarLevel(DdManager * dd, int index);
+EXTERN int cuddZddGetNegVarLevel(DdManager * dd, int index);
+EXTERN int cuddZddTreeSifting ARGS((DdManager *table, Cudd_ReorderingType method));
+EXTERN DdNode * cuddZddIsop ARGS((DdManager *dd, DdNode *L, DdNode *U, DdNode **zdd_I));
+EXTERN DdNode * cuddBddIsop ARGS((DdManager *dd, DdNode *L, DdNode *U));
+EXTERN DdNode * cuddMakeBddFromZddCover ARGS((DdManager *dd, DdNode *node));
+EXTERN int cuddZddLinearSifting ARGS((DdManager *table, int lower, int upper));
+EXTERN int cuddZddAlignToBdd ARGS((DdManager *table));
+EXTERN int cuddZddNextHigh ARGS((DdManager *table, int x));
+EXTERN int cuddZddNextLow ARGS((DdManager *table, int x));
+EXTERN int cuddZddUniqueCompare ARGS((int *ptr_x, int *ptr_y));
+EXTERN int cuddZddSwapInPlace ARGS((DdManager *table, int x, int y));
+EXTERN int cuddZddSwapping ARGS((DdManager *table, int lower, int upper, Cudd_ReorderingType heuristic));
+EXTERN int cuddZddSifting ARGS((DdManager *table, int lower, int upper));
+EXTERN DdNode * cuddZddIte ARGS((DdManager *dd, DdNode *f, DdNode *g, DdNode *h));
+EXTERN DdNode * cuddZddUnion ARGS((DdManager *zdd, DdNode *P, DdNode *Q));
+EXTERN DdNode * cuddZddIntersect ARGS((DdManager *zdd, DdNode *P, DdNode *Q));
+EXTERN DdNode * cuddZddDiff ARGS((DdManager *zdd, DdNode *P, DdNode *Q));
+EXTERN DdNode * cuddZddChangeAux ARGS((DdManager *zdd, DdNode *P, DdNode *zvar));
+EXTERN DdNode * cuddZddSubset1 ARGS((DdManager *dd, DdNode *P, int var));
+EXTERN DdNode * cuddZddSubset0 ARGS((DdManager *dd, DdNode *P, int var));
+EXTERN DdNode * cuddZddChange ARGS((DdManager *dd, DdNode *P, int var));
+EXTERN int cuddZddSymmCheck ARGS((DdManager *table, int x, int y));
+EXTERN int cuddZddSymmSifting ARGS((DdManager *table, int lower, int upper));
+EXTERN int cuddZddSymmSiftingConv ARGS((DdManager *table, int lower, int upper));
+EXTERN int cuddZddP ARGS((DdManager *zdd, DdNode *f));
+
+/**AutomaticEnd***************************************************************/
+
+#endif /* _CUDDINT */
diff --git a/src/bdd/cudd/cuddInteract.c b/src/bdd/cudd/cuddInteract.c
new file mode 100644
index 00000000..5a4ec79a
--- /dev/null
+++ b/src/bdd/cudd/cuddInteract.c
@@ -0,0 +1,402 @@
+/**CFile***********************************************************************
+
+ FileName [cuddInteract.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions to manipulate the variable interaction matrix.]
+
+ Description [Internal procedures included in this file:
+ <ul>
+ <li> cuddSetInteract()
+ <li> cuddTestInteract()
+ <li> cuddInitInteract()
+ </ul>
+ Static procedures included in this file:
+ <ul>
+ <li> ddSuppInteract()
+ <li> ddClearLocal()
+ <li> ddUpdateInteract()
+ <li> ddClearGlobal()
+ </ul>
+ The interaction matrix tells whether two variables are
+ both in the support of some function of the DD. The main use of the
+ interaction matrix is in the in-place swapping. Indeed, if two
+ variables do not interact, there is no arc connecting the two layers;
+ therefore, the swap can be performed in constant time, without
+ scanning the subtables. Another use of the interaction matrix is in
+ the computation of the lower bounds for sifting. Finally, the
+ interaction matrix can be used to speed up aggregation checks in
+ symmetric and group sifting.<p>
+ The computation of the interaction matrix is done with a series of
+ depth-first searches. The searches start from those nodes that have
+ only external references. The matrix is stored as a packed array of bits;
+ since it is symmetric, only the upper triangle is kept in memory.
+ As a final remark, we note that there may be variables that do
+ intercat, but that for a given variable order have no arc connecting
+ their layers when they are adjacent.]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#if SIZEOF_LONG == 8
+#define BPL 64
+#define LOGBPL 6
+#else
+#define BPL 32
+#define LOGBPL 5
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddInteract.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static void ddSuppInteract ARGS((DdNode *f, int *support));
+static void ddClearLocal ARGS((DdNode *f));
+static void ddUpdateInteract ARGS((DdManager *table, int *support));
+static void ddClearGlobal ARGS((DdManager *table));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Set interaction matrix entries.]
+
+ Description [Given a pair of variables 0 <= x < y < table->size,
+ sets the corresponding bit of the interaction matrix to 1.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+cuddSetInteract(
+ DdManager * table,
+ int x,
+ int y)
+{
+ int posn, word, bit;
+
+#ifdef DD_DEBUG
+ assert(x < y);
+ assert(y < table->size);
+ assert(x >= 0);
+#endif
+
+ posn = ((((table->size << 1) - x - 3) * x) >> 1) + y - 1;
+ word = posn >> LOGBPL;
+ bit = posn & (BPL-1);
+ table->interact[word] |= 1L << bit;
+
+} /* end of cuddSetInteract */
+
+
+/**Function********************************************************************
+
+ Synopsis [Test interaction matrix entries.]
+
+ Description [Given a pair of variables 0 <= x < y < table->size,
+ tests whether the corresponding bit of the interaction matrix is 1.
+ Returns the value of the bit.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddTestInteract(
+ DdManager * table,
+ int x,
+ int y)
+{
+ int posn, word, bit, result;
+
+ if (x > y) {
+ int tmp = x;
+ x = y;
+ y = tmp;
+ }
+#ifdef DD_DEBUG
+ assert(x < y);
+ assert(y < table->size);
+ assert(x >= 0);
+#endif
+
+ posn = ((((table->size << 1) - x - 3) * x) >> 1) + y - 1;
+ word = posn >> LOGBPL;
+ bit = posn & (BPL-1);
+ result = (table->interact[word] >> bit) & 1L;
+ return(result);
+
+} /* end of cuddTestInteract */
+
+
+/**Function********************************************************************
+
+ Synopsis [Initializes the interaction matrix.]
+
+ Description [Initializes the interaction matrix. The interaction
+ matrix is implemented as a bit vector storing the upper triangle of
+ the symmetric interaction matrix. The bit vector is kept in an array
+ of long integers. The computation is based on a series of depth-first
+ searches, one for each root of the DAG. Two flags are needed: The
+ local visited flag uses the LSB of the then pointer. The global
+ visited flag uses the LSB of the next pointer.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddInitInteract(
+ DdManager * table)
+{
+ int i,j,k;
+ int words;
+ long *interact;
+ int *support;
+ DdNode *f;
+ DdNode *sentinel = &(table->sentinel);
+ DdNodePtr *nodelist;
+ int slots;
+ int n = table->size;
+
+ words = ((n * (n-1)) >> (1 + LOGBPL)) + 1;
+ table->interact = interact = ALLOC(long,words);
+ if (interact == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (i = 0; i < words; i++) {
+ interact[i] = 0;
+ }
+
+ support = ALLOC(int,n);
+ if (support == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ FREE(interact);
+ return(0);
+ }
+
+ for (i = 0; i < n; i++) {
+ nodelist = table->subtables[i].nodelist;
+ slots = table->subtables[i].slots;
+ for (j = 0; j < slots; j++) {
+ f = nodelist[j];
+ while (f != sentinel) {
+ /* A node is a root of the DAG if it cannot be
+ ** reached by nodes above it. If a node was never
+ ** reached during the previous depth-first searches,
+ ** then it is a root, and we start a new depth-first
+ ** search from it.
+ */
+ if (!Cudd_IsComplement(f->next)) {
+ for (k = 0; k < n; k++) {
+ support[k] = 0;
+ }
+ ddSuppInteract(f,support);
+ ddClearLocal(f);
+ ddUpdateInteract(table,support);
+ }
+ f = Cudd_Regular(f->next);
+ }
+ }
+ }
+ ddClearGlobal(table);
+
+ FREE(support);
+ return(1);
+
+} /* end of cuddInitInteract */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Find the support of f.]
+
+ Description [Performs a DFS from f. Uses the LSB of the then pointer
+ as visited flag.]
+
+ SideEffects [Accumulates in support the variables on which f depends.]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+ddSuppInteract(
+ DdNode * f,
+ int * support)
+{
+ if (cuddIsConstant(f) || Cudd_IsComplement(cuddT(f))) {
+ return;
+ }
+
+ support[f->index] = 1;
+ ddSuppInteract(cuddT(f),support);
+ ddSuppInteract(Cudd_Regular(cuddE(f)),support);
+ /* mark as visited */
+ cuddT(f) = Cudd_Complement(cuddT(f));
+ f->next = Cudd_Complement(f->next);
+ return;
+
+} /* end of ddSuppInteract */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs a DFS from f, clearing the LSB of the then pointers.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+ddClearLocal(
+ DdNode * f)
+{
+ if (cuddIsConstant(f) || !Cudd_IsComplement(cuddT(f))) {
+ return;
+ }
+ /* clear visited flag */
+ cuddT(f) = Cudd_Regular(cuddT(f));
+ ddClearLocal(cuddT(f));
+ ddClearLocal(Cudd_Regular(cuddE(f)));
+ return;
+
+} /* end of ddClearLocal */
+
+
+/**Function********************************************************************
+
+ Synopsis [Marks as interacting all pairs of variables that appear in
+ support.]
+
+ Description [If support[i] == support[j] == 1, sets the (i,j) entry
+ of the interaction matrix to 1.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+ddUpdateInteract(
+ DdManager * table,
+ int * support)
+{
+ int i,j;
+ int n = table->size;
+
+ for (i = 0; i < n-1; i++) {
+ if (support[i] == 1) {
+ for (j = i+1; j < n; j++) {
+ if (support[j] == 1) {
+ cuddSetInteract(table,i,j);
+ }
+ }
+ }
+ }
+
+} /* end of ddUpdateInteract */
+
+
+/**Function********************************************************************
+
+ Synopsis [Scans the DD and clears the LSB of the next pointers.]
+
+ Description [The LSB of the next pointers are used as markers to tell
+ whether a node was reached by at least one DFS. Once the interaction
+ matrix is built, these flags are reset.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+ddClearGlobal(
+ DdManager * table)
+{
+ int i,j;
+ DdNode *f;
+ DdNode *sentinel = &(table->sentinel);
+ DdNodePtr *nodelist;
+ int slots;
+
+ for (i = 0; i < table->size; i++) {
+ nodelist = table->subtables[i].nodelist;
+ slots = table->subtables[i].slots;
+ for (j = 0; j < slots; j++) {
+ f = nodelist[j];
+ while (f != sentinel) {
+ f->next = Cudd_Regular(f->next);
+ f = f->next;
+ }
+ }
+ }
+
+} /* end of ddClearGlobal */
+
diff --git a/src/bdd/cudd/cuddLCache.c b/src/bdd/cudd/cuddLCache.c
new file mode 100644
index 00000000..72fbd48a
--- /dev/null
+++ b/src/bdd/cudd/cuddLCache.c
@@ -0,0 +1,1428 @@
+/**CFile***********************************************************************
+
+ FileName [cuddLCache.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions for local caches.]
+
+ Description [Internal procedures included in this module:
+ <ul>
+ <li> cuddLocalCacheInit()
+ <li> cuddLocalCacheQuit()
+ <li> cuddLocalCacheInsert()
+ <li> cuddLocalCacheLookup()
+ <li> cuddLocalCacheClearDead()
+ <li> cuddLocalCacheClearAll()
+ <li> cuddLocalCacheProfile()
+ <li> cuddHashTableInit()
+ <li> cuddHashTableQuit()
+ <li> cuddHashTableInsert()
+ <li> cuddHashTableLookup()
+ <li> cuddHashTableInsert2()
+ <li> cuddHashTableLookup2()
+ <li> cuddHashTableInsert3()
+ <li> cuddHashTableLookup3()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> cuddLocalCacheResize()
+ <li> ddLCHash()
+ <li> cuddLocalCacheAddToList()
+ <li> cuddLocalCacheRemoveFromList()
+ <li> cuddHashTableResize()
+ <li> cuddHashTableAlloc()
+ </ul> ]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define DD_MAX_HASHTABLE_DENSITY 2 /* tells when to resize a table */
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddLCache.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**Macro***********************************************************************
+
+ Synopsis [Computes hash function for keys of two operands.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [ddLCHash3 ddLCHash]
+
+******************************************************************************/
+#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
+#define ddLCHash2(f,g,shift) \
+((((unsigned)(unsigned long)(f) * DD_P1 + \
+ (unsigned)(unsigned long)(g)) * DD_P2) >> (shift))
+#else
+#define ddLCHash2(f,g,shift) \
+((((unsigned)(f) * DD_P1 + (unsigned)(g)) * DD_P2) >> (shift))
+#endif
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Computes hash function for keys of three operands.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [ddLCHash2 ddLCHash]
+
+******************************************************************************/
+#define ddLCHash3(f,g,h,shift) ddCHash2(f,g,h,shift)
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static void cuddLocalCacheResize ARGS((DdLocalCache *cache));
+DD_INLINE static unsigned int ddLCHash ARGS((DdNodePtr *key, unsigned int keysize, int shift));
+static void cuddLocalCacheAddToList ARGS((DdLocalCache *cache));
+static void cuddLocalCacheRemoveFromList ARGS((DdLocalCache *cache));
+static int cuddHashTableResize ARGS((DdHashTable *hash));
+DD_INLINE static DdHashItem * cuddHashTableAlloc ARGS((DdHashTable *hash));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Initializes a local computed table.]
+
+ Description [Initializes a computed table. Returns a pointer the
+ the new local cache in case of success; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddInitCache]
+
+******************************************************************************/
+DdLocalCache *
+cuddLocalCacheInit(
+ DdManager * manager /* manager */,
+ unsigned int keySize /* size of the key (number of operands) */,
+ unsigned int cacheSize /* Initial size of the cache */,
+ unsigned int maxCacheSize /* Size of the cache beyond which no resizing occurs */)
+{
+ DdLocalCache *cache;
+ int logSize;
+
+ cache = ALLOC(DdLocalCache,1);
+ if (cache == NULL) {
+ manager->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ cache->manager = manager;
+ cache->keysize = keySize;
+ cache->itemsize = (keySize + 1) * sizeof(DdNode *);
+#ifdef DD_CACHE_PROFILE
+ cache->itemsize += sizeof(ptrint);
+#endif
+ logSize = cuddComputeFloorLog2(ddMax(cacheSize,manager->slots/2));
+ cacheSize = 1 << logSize;
+ cache->item = (DdLocalCacheItem *)
+ ALLOC(char, cacheSize * cache->itemsize);
+ if (cache->item == NULL) {
+ manager->errorCode = CUDD_MEMORY_OUT;
+ FREE(cache);
+ return(NULL);
+ }
+ cache->slots = cacheSize;
+ cache->shift = sizeof(int) * 8 - logSize;
+ cache->maxslots = ddMin(maxCacheSize,manager->slots);
+ cache->minHit = manager->minHit;
+ /* Initialize to avoid division by 0 and immediate resizing. */
+ cache->lookUps = (double) (int) (cacheSize * cache->minHit + 1);
+ cache->hits = 0;
+ manager->memused += cacheSize * cache->itemsize + sizeof(DdLocalCache);
+
+ /* Initialize the cache. */
+ memset(cache->item, 0, cacheSize * cache->itemsize);
+
+ /* Add to manager's list of local caches for GC. */
+ cuddLocalCacheAddToList(cache);
+
+ return(cache);
+
+} /* end of cuddLocalCacheInit */
+
+
+/**Function********************************************************************
+
+ Synopsis [Shuts down a local computed table.]
+
+ Description [Initializes the computed table. It is called by
+ Cudd_Init. Returns a pointer the the new local cache in case of
+ success; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddLocalCacheInit]
+
+******************************************************************************/
+void
+cuddLocalCacheQuit(
+ DdLocalCache * cache /* cache to be shut down */)
+{
+ cache->manager->memused -=
+ cache->slots * cache->itemsize + sizeof(DdLocalCache);
+ cuddLocalCacheRemoveFromList(cache);
+ FREE(cache->item);
+ FREE(cache);
+
+ return;
+
+} /* end of cuddLocalCacheQuit */
+
+
+/**Function********************************************************************
+
+ Synopsis [Inserts a result in a local cache.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+cuddLocalCacheInsert(
+ DdLocalCache * cache,
+ DdNodePtr * key,
+ DdNode * value)
+{
+ unsigned int posn;
+ DdLocalCacheItem *entry;
+
+ posn = ddLCHash(key,cache->keysize,cache->shift);
+ entry = (DdLocalCacheItem *) ((char *) cache->item +
+ posn * cache->itemsize);
+ memcpy(entry->key,key,cache->keysize * sizeof(DdNode *));
+ entry->value = value;
+#ifdef DD_CACHE_PROFILE
+ entry->count++;
+#endif
+
+} /* end of cuddLocalCacheInsert */
+
+
+/**Function********************************************************************
+
+ Synopsis [Looks up in a local cache.]
+
+ Description [Looks up in a local cache. Returns the result if found;
+ it returns NULL if no result is found.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+cuddLocalCacheLookup(
+ DdLocalCache * cache,
+ DdNodePtr * key)
+{
+ unsigned int posn;
+ DdLocalCacheItem *entry;
+ DdNode *value;
+
+ cache->lookUps++;
+ posn = ddLCHash(key,cache->keysize,cache->shift);
+ entry = (DdLocalCacheItem *) ((char *) cache->item +
+ posn * cache->itemsize);
+ if (entry->value != NULL &&
+ memcmp(key,entry->key,cache->keysize*sizeof(DdNode *)) == 0) {
+ cache->hits++;
+ value = Cudd_Regular(entry->value);
+ if (value->ref == 0) {
+ cuddReclaim(cache->manager,value);
+ }
+ return(entry->value);
+ }
+
+ /* Cache miss: decide whether to resize */
+
+ if (cache->slots < cache->maxslots &&
+ cache->hits > cache->lookUps * cache->minHit) {
+ cuddLocalCacheResize(cache);
+ }
+
+ return(NULL);
+
+} /* end of cuddLocalCacheLookup */
+
+
+/**Function********************************************************************
+
+ Synopsis [Clears the dead entries of the local caches of a manager.]
+
+ Description [Clears the dead entries of the local caches of a manager.
+ Used during garbage collection.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+cuddLocalCacheClearDead(
+ DdManager * manager)
+{
+ DdLocalCache *cache = manager->localCaches;
+ unsigned int keysize;
+ unsigned int itemsize;
+ unsigned int slots;
+ DdLocalCacheItem *item;
+ DdNodePtr *key;
+ unsigned int i, j;
+
+ while (cache != NULL) {
+ keysize = cache->keysize;
+ itemsize = cache->itemsize;
+ slots = cache->slots;
+ item = cache->item;
+ for (i = 0; i < slots; i++) {
+ if (item->value != NULL && Cudd_Regular(item->value)->ref == 0) {
+ item->value = NULL;
+ } else {
+ key = item->key;
+ for (j = 0; j < keysize; j++) {
+ if (Cudd_Regular(key[j])->ref == 0) {
+ item->value = NULL;
+ break;
+ }
+ }
+ }
+ item = (DdLocalCacheItem *) ((char *) item + itemsize);
+ }
+ cache = cache->next;
+ }
+ return;
+
+} /* end of cuddLocalCacheClearDead */
+
+
+/**Function********************************************************************
+
+ Synopsis [Clears the local caches of a manager.]
+
+ Description [Clears the local caches of a manager.
+ Used before reordering.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+cuddLocalCacheClearAll(
+ DdManager * manager)
+{
+ DdLocalCache *cache = manager->localCaches;
+
+ while (cache != NULL) {
+ memset(cache->item, 0, cache->slots * cache->itemsize);
+ cache = cache->next;
+ }
+ return;
+
+} /* end of cuddLocalCacheClearAll */
+
+
+#ifdef DD_CACHE_PROFILE
+
+#define DD_HYSTO_BINS 8
+
+/**Function********************************************************************
+
+ Synopsis [Computes and prints a profile of a local cache usage.]
+
+ Description [Computes and prints a profile of a local cache usage.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddLocalCacheProfile(
+ DdLocalCache * cache)
+{
+ double count, mean, meansq, stddev, expected;
+ long max, min;
+ int imax, imin;
+ int i, retval, slots;
+ long *hystogram;
+ int nbins = DD_HYSTO_BINS;
+ int bin;
+ long thiscount;
+ double totalcount;
+ int nzeroes;
+ DdLocalCacheItem *entry;
+ FILE *fp = cache->manager->out;
+
+ slots = cache->slots;
+
+ meansq = mean = expected = 0.0;
+ max = min = (long) cache->item[0].count;
+ imax = imin = nzeroes = 0;
+ totalcount = 0.0;
+
+ hystogram = ALLOC(long, nbins);
+ if (hystogram == NULL) {
+ return(0);
+ }
+ for (i = 0; i < nbins; i++) {
+ hystogram[i] = 0;
+ }
+
+ for (i = 0; i < slots; i++) {
+ entry = (DdLocalCacheItem *) ((char *) cache->item +
+ i * cache->itemsize);
+ thiscount = (long) entry->count;
+ if (thiscount > max) {
+ max = thiscount;
+ imax = i;
+ }
+ if (thiscount < min) {
+ min = thiscount;
+ imin = i;
+ }
+ if (thiscount == 0) {
+ nzeroes++;
+ }
+ count = (double) thiscount;
+ mean += count;
+ meansq += count * count;
+ totalcount += count;
+ expected += count * (double) i;
+ bin = (i * nbins) / slots;
+ hystogram[bin] += thiscount;
+ }
+ mean /= (double) slots;
+ meansq /= (double) slots;
+ stddev = sqrt(meansq - mean*mean);
+
+ retval = fprintf(fp,"Cache stats: slots = %d average = %g ", slots, mean);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"standard deviation = %g\n", stddev);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Cache max accesses = %ld for slot %d\n", max, imax);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Cache min accesses = %ld for slot %d\n", min, imin);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,"Cache unused slots = %d\n", nzeroes);
+ if (retval == EOF) return(0);
+
+ if (totalcount) {
+ expected /= totalcount;
+ retval = fprintf(fp,"Cache access hystogram for %d bins", nbins);
+ if (retval == EOF) return(0);
+ retval = fprintf(fp," (expected bin value = %g)\n# ", expected);
+ if (retval == EOF) return(0);
+ for (i = nbins - 1; i>=0; i--) {
+ retval = fprintf(fp,"%ld ", hystogram[i]);
+ if (retval == EOF) return(0);
+ }
+ retval = fprintf(fp,"\n");
+ if (retval == EOF) return(0);
+ }
+
+ FREE(hystogram);
+ return(1);
+
+} /* end of cuddLocalCacheProfile */
+#endif
+
+
+/**Function********************************************************************
+
+ Synopsis [Initializes a hash table.]
+
+ Description [Initializes a hash table. Returns a pointer to the new
+ table if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddHashTableQuit]
+
+******************************************************************************/
+DdHashTable *
+cuddHashTableInit(
+ DdManager * manager,
+ unsigned int keySize,
+ unsigned int initSize)
+{
+ DdHashTable *hash;
+ int logSize;
+
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ hash = ALLOC(DdHashTable, 1);
+ if (hash == NULL) {
+ manager->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ hash->keysize = keySize;
+ hash->manager = manager;
+ hash->memoryList = NULL;
+ hash->nextFree = NULL;
+ hash->itemsize = (keySize + 1) * sizeof(DdNode *) +
+ sizeof(ptrint) + sizeof(DdHashItem *);
+ /* We have to guarantee that the shift be < 32. */
+ if (initSize < 2) initSize = 2;
+ logSize = cuddComputeFloorLog2(initSize);
+ hash->numBuckets = 1 << logSize;
+ hash->shift = sizeof(int) * 8 - logSize;
+ hash->bucket = ALLOC(DdHashItem *, hash->numBuckets);
+ if (hash->bucket == NULL) {
+ manager->errorCode = CUDD_MEMORY_OUT;
+ FREE(hash);
+ return(NULL);
+ }
+ memset(hash->bucket, 0, hash->numBuckets * sizeof(DdHashItem *));
+ hash->size = 0;
+ hash->maxsize = hash->numBuckets * DD_MAX_HASHTABLE_DENSITY;
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+ return(hash);
+
+} /* end of cuddHashTableInit */
+
+
+/**Function********************************************************************
+
+ Synopsis [Shuts down a hash table.]
+
+ Description [Shuts down a hash table, dereferencing all the values.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddHashTableInit]
+
+******************************************************************************/
+void
+cuddHashTableQuit(
+ DdHashTable * hash)
+{
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ unsigned int i;
+ DdManager *dd = hash->manager;
+ DdHashItem *bucket;
+ DdHashItem **memlist, **nextmem;
+ unsigned int numBuckets = hash->numBuckets;
+
+ for (i = 0; i < numBuckets; i++) {
+ bucket = hash->bucket[i];
+ while (bucket != NULL) {
+ Cudd_RecursiveDeref(dd, bucket->value);
+ bucket = bucket->next;
+ }
+ }
+
+ memlist = hash->memoryList;
+ while (memlist != NULL) {
+ nextmem = (DdHashItem **) memlist[0];
+ FREE(memlist);
+ memlist = nextmem;
+ }
+
+ FREE(hash->bucket);
+ FREE(hash);
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+
+ return;
+
+} /* end of cuddHashTableQuit */
+
+
+/**Function********************************************************************
+
+ Synopsis [Inserts an item in a hash table.]
+
+ Description [Inserts an item in a hash table when the key has more than
+ three pointers. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [[cuddHashTableInsert1 cuddHashTableInsert2 cuddHashTableInsert3
+ cuddHashTableLookup]
+
+******************************************************************************/
+int
+cuddHashTableInsert(
+ DdHashTable * hash,
+ DdNodePtr * key,
+ DdNode * value,
+ ptrint count)
+{
+ int result;
+ unsigned int posn;
+ DdHashItem *item;
+ unsigned int i;
+
+#ifdef DD_DEBUG
+ assert(hash->keysize > 3);
+#endif
+
+ if (hash->size > hash->maxsize) {
+ result = cuddHashTableResize(hash);
+ if (result == 0) return(0);
+ }
+ item = cuddHashTableAlloc(hash);
+ if (item == NULL) return(0);
+ hash->size++;
+ item->value = value;
+ cuddRef(value);
+ item->count = count;
+ for (i = 0; i < hash->keysize; i++) {
+ item->key[i] = key[i];
+ }
+ posn = ddLCHash(key,hash->keysize,hash->shift);
+ item->next = hash->bucket[posn];
+ hash->bucket[posn] = item;
+
+ return(1);
+
+} /* end of cuddHashTableInsert */
+
+
+/**Function********************************************************************
+
+ Synopsis [Looks up a key in a hash table.]
+
+ Description [Looks up a key consisting of more than three pointers
+ in a hash table. Returns the value associated to the key if there
+ is an entry for the given key in the table; NULL otherwise. If the
+ entry is present, its reference counter is decremented if not
+ saturated. If the counter reaches 0, the value of the entry is
+ dereferenced, and the entry is returned to the free list.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddHashTableLookup1 cuddHashTableLookup2 cuddHashTableLookup3
+ cuddHashTableInsert]
+
+******************************************************************************/
+DdNode *
+cuddHashTableLookup(
+ DdHashTable * hash,
+ DdNodePtr * key)
+{
+ unsigned int posn;
+ DdHashItem *item, *prev;
+ unsigned int i, keysize;
+
+#ifdef DD_DEBUG
+ assert(hash->keysize > 3);
+#endif
+
+ posn = ddLCHash(key,hash->keysize,hash->shift);
+ item = hash->bucket[posn];
+ prev = NULL;
+
+ keysize = hash->keysize;
+ while (item != NULL) {
+ DdNodePtr *key2 = item->key;
+ int equal = 1;
+ for (i = 0; i < keysize; i++) {
+ if (key[i] != key2[i]) {
+ equal = 0;
+ break;
+ }
+ }
+ if (equal) {
+ DdNode *value = item->value;
+ cuddSatDec(item->count);
+ if (item->count == 0) {
+ cuddDeref(value);
+ if (prev == NULL) {
+ hash->bucket[posn] = item->next;
+ } else {
+ prev->next = item->next;
+ }
+ item->next = hash->nextFree;
+ hash->nextFree = item;
+ hash->size--;
+ }
+ return(value);
+ }
+ prev = item;
+ item = item->next;
+ }
+ return(NULL);
+
+} /* end of cuddHashTableLookup */
+
+
+/**Function********************************************************************
+
+ Synopsis [Inserts an item in a hash table.]
+
+ Description [Inserts an item in a hash table when the key is one pointer.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddHashTableInsert cuddHashTableInsert2 cuddHashTableInsert3
+ cuddHashTableLookup1]
+
+******************************************************************************/
+int
+cuddHashTableInsert1(
+ DdHashTable * hash,
+ DdNode * f,
+ DdNode * value,
+ ptrint count)
+{
+ int result;
+ unsigned int posn;
+ DdHashItem *item;
+
+#ifdef DD_DEBUG
+ assert(hash->keysize == 1);
+#endif
+
+ if (hash->size > hash->maxsize) {
+ result = cuddHashTableResize(hash);
+ if (result == 0) return(0);
+ }
+ item = cuddHashTableAlloc(hash);
+ if (item == NULL) return(0);
+ hash->size++;
+ item->value = value;
+ cuddRef(value);
+ item->count = count;
+ item->key[0] = f;
+ posn = ddLCHash2(f,f,hash->shift);
+ item->next = hash->bucket[posn];
+ hash->bucket[posn] = item;
+
+ return(1);
+
+} /* end of cuddHashTableInsert1 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Looks up a key consisting of one pointer in a hash table.]
+
+ Description [Looks up a key consisting of one pointer in a hash table.
+ Returns the value associated to the key if there is an entry for the given
+ key in the table; NULL otherwise. If the entry is present, its reference
+ counter is decremented if not saturated. If the counter reaches 0, the
+ value of the entry is dereferenced, and the entry is returned to the free
+ list.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddHashTableLookup cuddHashTableLookup2 cuddHashTableLookup3
+ cuddHashTableInsert1]
+
+******************************************************************************/
+DdNode *
+cuddHashTableLookup1(
+ DdHashTable * hash,
+ DdNode * f)
+{
+ unsigned int posn;
+ DdHashItem *item, *prev;
+
+#ifdef DD_DEBUG
+ assert(hash->keysize == 1);
+#endif
+
+ posn = ddLCHash2(f,f,hash->shift);
+ item = hash->bucket[posn];
+ prev = NULL;
+
+ while (item != NULL) {
+ DdNodePtr *key = item->key;
+ if (f == key[0]) {
+ DdNode *value = item->value;
+ cuddSatDec(item->count);
+ if (item->count == 0) {
+ cuddDeref(value);
+ if (prev == NULL) {
+ hash->bucket[posn] = item->next;
+ } else {
+ prev->next = item->next;
+ }
+ item->next = hash->nextFree;
+ hash->nextFree = item;
+ hash->size--;
+ }
+ return(value);
+ }
+ prev = item;
+ item = item->next;
+ }
+ return(NULL);
+
+} /* end of cuddHashTableLookup1 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Inserts an item in a hash table.]
+
+ Description [Inserts an item in a hash table when the key is
+ composed of two pointers. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddHashTableInsert cuddHashTableInsert1 cuddHashTableInsert3
+ cuddHashTableLookup2]
+
+******************************************************************************/
+int
+cuddHashTableInsert2(
+ DdHashTable * hash,
+ DdNode * f,
+ DdNode * g,
+ DdNode * value,
+ ptrint count)
+{
+ int result;
+ unsigned int posn;
+ DdHashItem *item;
+
+#ifdef DD_DEBUG
+ assert(hash->keysize == 2);
+#endif
+
+ if (hash->size > hash->maxsize) {
+ result = cuddHashTableResize(hash);
+ if (result == 0) return(0);
+ }
+ item = cuddHashTableAlloc(hash);
+ if (item == NULL) return(0);
+ hash->size++;
+ item->value = value;
+ cuddRef(value);
+ item->count = count;
+ item->key[0] = f;
+ item->key[1] = g;
+ posn = ddLCHash2(f,g,hash->shift);
+ item->next = hash->bucket[posn];
+ hash->bucket[posn] = item;
+
+ return(1);
+
+} /* end of cuddHashTableInsert2 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Looks up a key consisting of two pointers in a hash table.]
+
+ Description [Looks up a key consisting of two pointer in a hash table.
+ Returns the value associated to the key if there is an entry for the given
+ key in the table; NULL otherwise. If the entry is present, its reference
+ counter is decremented if not saturated. If the counter reaches 0, the
+ value of the entry is dereferenced, and the entry is returned to the free
+ list.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddHashTableLookup cuddHashTableLookup1 cuddHashTableLookup3
+ cuddHashTableInsert2]
+
+******************************************************************************/
+DdNode *
+cuddHashTableLookup2(
+ DdHashTable * hash,
+ DdNode * f,
+ DdNode * g)
+{
+ unsigned int posn;
+ DdHashItem *item, *prev;
+
+#ifdef DD_DEBUG
+ assert(hash->keysize == 2);
+#endif
+
+ posn = ddLCHash2(f,g,hash->shift);
+ item = hash->bucket[posn];
+ prev = NULL;
+
+ while (item != NULL) {
+ DdNodePtr *key = item->key;
+ if ((f == key[0]) && (g == key[1])) {
+ DdNode *value = item->value;
+ cuddSatDec(item->count);
+ if (item->count == 0) {
+ cuddDeref(value);
+ if (prev == NULL) {
+ hash->bucket[posn] = item->next;
+ } else {
+ prev->next = item->next;
+ }
+ item->next = hash->nextFree;
+ hash->nextFree = item;
+ hash->size--;
+ }
+ return(value);
+ }
+ prev = item;
+ item = item->next;
+ }
+ return(NULL);
+
+} /* end of cuddHashTableLookup2 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Inserts an item in a hash table.]
+
+ Description [Inserts an item in a hash table when the key is
+ composed of three pointers. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddHashTableInsert cuddHashTableInsert1 cuddHashTableInsert2
+ cuddHashTableLookup3]
+
+******************************************************************************/
+int
+cuddHashTableInsert3(
+ DdHashTable * hash,
+ DdNode * f,
+ DdNode * g,
+ DdNode * h,
+ DdNode * value,
+ ptrint count)
+{
+ int result;
+ unsigned int posn;
+ DdHashItem *item;
+
+#ifdef DD_DEBUG
+ assert(hash->keysize == 3);
+#endif
+
+ if (hash->size > hash->maxsize) {
+ result = cuddHashTableResize(hash);
+ if (result == 0) return(0);
+ }
+ item = cuddHashTableAlloc(hash);
+ if (item == NULL) return(0);
+ hash->size++;
+ item->value = value;
+ cuddRef(value);
+ item->count = count;
+ item->key[0] = f;
+ item->key[1] = g;
+ item->key[2] = h;
+ posn = ddLCHash3(f,g,h,hash->shift);
+ item->next = hash->bucket[posn];
+ hash->bucket[posn] = item;
+
+ return(1);
+
+} /* end of cuddHashTableInsert3 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Looks up a key consisting of three pointers in a hash table.]
+
+ Description [Looks up a key consisting of three pointers in a hash table.
+ Returns the value associated to the key if there is an entry for the given
+ key in the table; NULL otherwise. If the entry is present, its reference
+ counter is decremented if not saturated. If the counter reaches 0, the
+ value of the entry is dereferenced, and the entry is returned to the free
+ list.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddHashTableLookup cuddHashTableLookup1 cuddHashTableLookup2
+ cuddHashTableInsert3]
+
+******************************************************************************/
+DdNode *
+cuddHashTableLookup3(
+ DdHashTable * hash,
+ DdNode * f,
+ DdNode * g,
+ DdNode * h)
+{
+ unsigned int posn;
+ DdHashItem *item, *prev;
+
+#ifdef DD_DEBUG
+ assert(hash->keysize == 3);
+#endif
+
+ posn = ddLCHash3(f,g,h,hash->shift);
+ item = hash->bucket[posn];
+ prev = NULL;
+
+ while (item != NULL) {
+ DdNodePtr *key = item->key;
+ if ((f == key[0]) && (g == key[1]) && (h == key[2])) {
+ DdNode *value = item->value;
+ cuddSatDec(item->count);
+ if (item->count == 0) {
+ cuddDeref(value);
+ if (prev == NULL) {
+ hash->bucket[posn] = item->next;
+ } else {
+ prev->next = item->next;
+ }
+ item->next = hash->nextFree;
+ hash->nextFree = item;
+ hash->size--;
+ }
+ return(value);
+ }
+ prev = item;
+ item = item->next;
+ }
+ return(NULL);
+
+} /* end of cuddHashTableLookup3 */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Resizes a local cache.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+cuddLocalCacheResize(
+ DdLocalCache * cache)
+{
+ DdLocalCacheItem *item, *olditem, *entry, *old;
+ int i, shift;
+ unsigned int posn;
+ unsigned int slots, oldslots;
+ extern void (*MMoutOfMemory)(long);
+ void (*saveHandler)(long);
+
+ olditem = cache->item;
+ oldslots = cache->slots;
+ slots = cache->slots = oldslots << 1;
+
+#ifdef DD_VERBOSE
+ (void) fprintf(cache->manager->err,
+ "Resizing local cache from %d to %d entries\n",
+ oldslots, slots);
+ (void) fprintf(cache->manager->err,
+ "\thits = %.0f\tlookups = %.0f\thit ratio = %5.3f\n",
+ cache->hits, cache->lookUps, cache->hits / cache->lookUps);
+#endif
+
+ saveHandler = MMoutOfMemory;
+ MMoutOfMemory = Cudd_OutOfMem;
+ cache->item = item =
+ (DdLocalCacheItem *) ALLOC(char, slots * cache->itemsize);
+ MMoutOfMemory = saveHandler;
+ /* If we fail to allocate the new table we just give up. */
+ if (item == NULL) {
+#ifdef DD_VERBOSE
+ (void) fprintf(cache->manager->err,"Resizing failed. Giving up.\n");
+#endif
+ cache->slots = oldslots;
+ cache->item = olditem;
+ /* Do not try to resize again. */
+ cache->maxslots = oldslots - 1;
+ return;
+ }
+ shift = --(cache->shift);
+ cache->manager->memused += (slots - oldslots) * cache->itemsize;
+
+ /* Clear new cache. */
+ memset(item, 0, slots * cache->itemsize);
+
+ /* Copy from old cache to new one. */
+ for (i = 0; (unsigned) i < oldslots; i++) {
+ old = (DdLocalCacheItem *) ((char *) olditem + i * cache->itemsize);
+ if (old->value != NULL) {
+ posn = ddLCHash(old->key,cache->keysize,slots);
+ entry = (DdLocalCacheItem *) ((char *) item +
+ posn * cache->itemsize);
+ memcpy(entry->key,old->key,cache->keysize*sizeof(DdNode *));
+ entry->value = old->value;
+ }
+ }
+
+ FREE(olditem);
+
+ /* Reinitialize measurements so as to avoid division by 0 and
+ ** immediate resizing.
+ */
+ cache->lookUps = (double) (int) (slots * cache->minHit + 1);
+ cache->hits = 0;
+
+} /* end of cuddLocalCacheResize */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the hash value for a local cache.]
+
+ Description [Computes the hash value for a local cache. Returns the
+ bucket index.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DD_INLINE
+static unsigned int
+ddLCHash(
+ DdNodePtr * key,
+ unsigned int keysize,
+ int shift)
+{
+ unsigned int val = (unsigned int) (ptrint) key[0];
+ unsigned int i;
+
+ for (i = 1; i < keysize; i++) {
+ val = val * DD_P1 + (int) (ptrint) key[i];
+ }
+
+ return(val >> shift);
+
+} /* end of ddLCHash */
+
+
+/**Function********************************************************************
+
+ Synopsis [Inserts a local cache in the manager list.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+cuddLocalCacheAddToList(
+ DdLocalCache * cache)
+{
+ DdManager *manager = cache->manager;
+
+ cache->next = manager->localCaches;
+ manager->localCaches = cache;
+ return;
+
+} /* end of cuddLocalCacheAddToList */
+
+
+/**Function********************************************************************
+
+ Synopsis [Removes a local cache from the manager list.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+cuddLocalCacheRemoveFromList(
+ DdLocalCache * cache)
+{
+ DdManager *manager = cache->manager;
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ DdLocalCache **prevCache, *nextCache;
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+
+ prevCache = &(manager->localCaches);
+ nextCache = manager->localCaches;
+
+ while (nextCache != NULL) {
+ if (nextCache == cache) {
+ *prevCache = nextCache->next;
+ return;
+ }
+ prevCache = &(nextCache->next);
+ nextCache = nextCache->next;
+ }
+ return; /* should never get here */
+
+} /* end of cuddLocalCacheRemoveFromList */
+
+
+/**Function********************************************************************
+
+ Synopsis [Resizes a hash table.]
+
+ Description [Resizes a hash table. Returns 1 if successful; 0
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddHashTableInsert]
+
+******************************************************************************/
+static int
+cuddHashTableResize(
+ DdHashTable * hash)
+{
+ int j;
+ unsigned int posn;
+ DdHashItem *item;
+ DdHashItem *next;
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ DdNode **key;
+ int numBuckets;
+ DdHashItem **buckets;
+ DdHashItem **oldBuckets = hash->bucket;
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+ int shift;
+ int oldNumBuckets = hash->numBuckets;
+ extern void (*MMoutOfMemory)(long);
+ void (*saveHandler)(long);
+
+ /* Compute the new size of the table. */
+ numBuckets = oldNumBuckets << 1;
+ saveHandler = MMoutOfMemory;
+ MMoutOfMemory = Cudd_OutOfMem;
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ buckets = ALLOC(DdHashItem *, numBuckets);
+ MMoutOfMemory = saveHandler;
+ if (buckets == NULL) {
+ hash->maxsize <<= 1;
+ return(1);
+ }
+
+ hash->bucket = buckets;
+ hash->numBuckets = numBuckets;
+ shift = --(hash->shift);
+ hash->maxsize <<= 1;
+ memset(buckets, 0, numBuckets * sizeof(DdHashItem *));
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+ if (hash->keysize == 1) {
+ for (j = 0; j < oldNumBuckets; j++) {
+ item = oldBuckets[j];
+ while (item != NULL) {
+ next = item->next;
+ key = item->key;
+ posn = ddLCHash2(key[0], key[0], shift);
+ item->next = buckets[posn];
+ buckets[posn] = item;
+ item = next;
+ }
+ }
+ } else if (hash->keysize == 2) {
+ for (j = 0; j < oldNumBuckets; j++) {
+ item = oldBuckets[j];
+ while (item != NULL) {
+ next = item->next;
+ key = item->key;
+ posn = ddLCHash2(key[0], key[1], shift);
+ item->next = buckets[posn];
+ buckets[posn] = item;
+ item = next;
+ }
+ }
+ } else if (hash->keysize == 3) {
+ for (j = 0; j < oldNumBuckets; j++) {
+ item = oldBuckets[j];
+ while (item != NULL) {
+ next = item->next;
+ key = item->key;
+ posn = ddLCHash3(key[0], key[1], key[2], shift);
+ item->next = buckets[posn];
+ buckets[posn] = item;
+ item = next;
+ }
+ }
+ } else {
+ for (j = 0; j < oldNumBuckets; j++) {
+ item = oldBuckets[j];
+ while (item != NULL) {
+ next = item->next;
+ posn = ddLCHash(item->key, hash->keysize, shift);
+ item->next = buckets[posn];
+ buckets[posn] = item;
+ item = next;
+ }
+ }
+ }
+ FREE(oldBuckets);
+ return(1);
+
+} /* end of cuddHashTableResize */
+
+
+/**Function********************************************************************
+
+ Synopsis [Fast storage allocation for items in a hash table.]
+
+ Description [Fast storage allocation for items in a hash table. The
+ first 4 bytes of a chunk contain a pointer to the next block; the
+ rest contains DD_MEM_CHUNK spaces for hash items. Returns a pointer to
+ a new item if successful; NULL is memory is full.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddAllocNode cuddDynamicAllocNode]
+
+******************************************************************************/
+DD_INLINE
+static DdHashItem *
+cuddHashTableAlloc(
+ DdHashTable * hash)
+{
+ int i;
+ unsigned int itemsize = hash->itemsize;
+ extern void (*MMoutOfMemory)(long);
+ void (*saveHandler)(long);
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ DdHashItem **mem, *thisOne, *next, *item;
+
+ if (hash->nextFree == NULL) {
+ saveHandler = MMoutOfMemory;
+ MMoutOfMemory = Cudd_OutOfMem;
+ mem = (DdHashItem **) ALLOC(char,(DD_MEM_CHUNK+1) * itemsize);
+ MMoutOfMemory = saveHandler;
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+ if (mem == NULL) {
+ if (hash->manager->stash != NULL) {
+ FREE(hash->manager->stash);
+ hash->manager->stash = NULL;
+ /* Inhibit resizing of tables. */
+ hash->manager->maxCacheHard = hash->manager->cacheSlots - 1;
+ hash->manager->cacheSlack = -(hash->manager->cacheSlots + 1);
+ for (i = 0; i < hash->manager->size; i++) {
+ hash->manager->subtables[i].maxKeys <<= 2;
+ }
+ hash->manager->gcFrac = 0.2;
+ hash->manager->minDead =
+ (unsigned) (0.2 * (double) hash->manager->slots);
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ mem = (DdHashItem **) ALLOC(char,(DD_MEM_CHUNK+1) * itemsize);
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+ }
+ if (mem == NULL) {
+ (*MMoutOfMemory)((DD_MEM_CHUNK + 1) * itemsize);
+ hash->manager->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ }
+
+ mem[0] = (DdHashItem *) hash->memoryList;
+ hash->memoryList = mem;
+
+ thisOne = (DdHashItem *) ((char *) mem + itemsize);
+ hash->nextFree = thisOne;
+ for (i = 1; i < DD_MEM_CHUNK; i++) {
+ next = (DdHashItem *) ((char *) thisOne + itemsize);
+ thisOne->next = next;
+ thisOne = next;
+ }
+
+ thisOne->next = NULL;
+
+ }
+ item = hash->nextFree;
+ hash->nextFree = item->next;
+ return(item);
+
+} /* end of cuddHashTableAlloc */
diff --git a/src/bdd/cudd/cuddLevelQ.c b/src/bdd/cudd/cuddLevelQ.c
new file mode 100644
index 00000000..c4c621e7
--- /dev/null
+++ b/src/bdd/cudd/cuddLevelQ.c
@@ -0,0 +1,533 @@
+/**CFile***********************************************************************
+
+ FileName [cuddLevelQ.c]
+
+ PackageName [cudd]
+
+ Synopsis [Procedure to manage level queues.]
+
+ Description [The functions in this file allow an application to
+ easily manipulate a queue where nodes are prioritized by level. The
+ emphasis is on efficiency. Therefore, the queue items can have
+ variable size. If the application does not need to attach
+ information to the nodes, it can declare the queue items to be of
+ type DdQueueItem. Otherwise, it can declare them to be of a
+ structure type such that the first three fields are data
+ pointers. The third pointer points to the node. The first two
+ pointers are used by the level queue functions. The remaining fields
+ are initialized to 0 when a new item is created, and are then left
+ to the exclusive use of the application. On the DEC Alphas the three
+ pointers must be 32-bit pointers when CUDD is compiled with 32-bit
+ pointers. The level queue functions make sure that each node
+ appears at most once in the queue. They do so by keeping a hash
+ table where the node is used as key. Queue items are recycled via a
+ free list for efficiency.
+
+ Internal procedures provided by this module:
+ <ul>
+ <li> cuddLevelQueueInit()
+ <li> cuddLevelQueueQuit()
+ <li> cuddLevelQueueEnqueue()
+ <li> cuddLevelQueueDequeue()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> hashLookup()
+ <li> hashInsert()
+ <li> hashDelete()
+ <li> hashResize()
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no
+ warranty about the suitability of this software for any
+ purpose. It is presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddLevelQ.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**Macro***********************************************************************
+
+ Synopsis [Hash function for the table of a level queue.]
+
+ Description [Hash function for the table of a level queue.]
+
+ SideEffects [None]
+
+ SeeAlso [hashInsert hashLookup hashDelete]
+
+******************************************************************************/
+#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
+#define lqHash(key,shift) \
+(((unsigned)(unsigned long)(key) * DD_P1) >> (shift))
+#else
+#define lqHash(key,shift) \
+(((unsigned)(key) * DD_P1) >> (shift))
+#endif
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static DdQueueItem * hashLookup ARGS((DdLevelQueue *queue, void *key));
+static int hashInsert ARGS((DdLevelQueue *queue, DdQueueItem *item));
+static void hashDelete ARGS((DdLevelQueue *queue, DdQueueItem *item));
+static int hashResize ARGS((DdLevelQueue *queue));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Initializes a level queue.]
+
+ Description [Initializes a level queue. A level queue is a queue
+ where inserts are based on the levels of the nodes. Within each
+ level the policy is FIFO. Level queues are useful in traversing a
+ BDD top-down. Queue items are kept in a free list when dequeued for
+ efficiency. Returns a pointer to the new queue if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddLevelQueueQuit cuddLevelQueueEnqueue cuddLevelQueueDequeue]
+
+******************************************************************************/
+DdLevelQueue *
+cuddLevelQueueInit(
+ int levels /* number of levels */,
+ int itemSize /* size of the item */,
+ int numBuckets /* initial number of hash buckets */)
+{
+ DdLevelQueue *queue;
+ int logSize;
+
+ queue = ALLOC(DdLevelQueue,1);
+ if (queue == NULL)
+ return(NULL);
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ /* Keep pointers to the insertion points for all levels. */
+ queue->last = ALLOC(DdQueueItem *, levels);
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+ if (queue->last == NULL) {
+ FREE(queue);
+ return(NULL);
+ }
+ /* Use a hash table to test for uniqueness. */
+ if (numBuckets < 2) numBuckets = 2;
+ logSize = cuddComputeFloorLog2(numBuckets);
+ queue->numBuckets = 1 << logSize;
+ queue->shift = sizeof(int) * 8 - logSize;
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ queue->buckets = ALLOC(DdQueueItem *, queue->numBuckets);
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+ if (queue->buckets == NULL) {
+ FREE(queue->last);
+ FREE(queue);
+ return(NULL);
+ }
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ memset(queue->last, 0, levels * sizeof(DdQueueItem *));
+ memset(queue->buckets, 0, queue->numBuckets * sizeof(DdQueueItem *));
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+ queue->first = NULL;
+ queue->freelist = NULL;
+ queue->levels = levels;
+ queue->itemsize = itemSize;
+ queue->size = 0;
+ queue->maxsize = queue->numBuckets * DD_MAX_SUBTABLE_DENSITY;
+ return(queue);
+
+} /* end of cuddLevelQueueInit */
+
+
+/**Function********************************************************************
+
+ Synopsis [Shuts down a level queue.]
+
+ Description [Shuts down a level queue and releases all the
+ associated memory.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddLevelQueueInit]
+
+******************************************************************************/
+void
+cuddLevelQueueQuit(
+ DdLevelQueue * queue)
+{
+ DdQueueItem *item;
+
+ while (queue->freelist != NULL) {
+ item = queue->freelist;
+ queue->freelist = item->next;
+ FREE(item);
+ }
+ while (queue->first != NULL) {
+ item = (DdQueueItem *) queue->first;
+ queue->first = item->next;
+ FREE(item);
+ }
+ FREE(queue->buckets);
+ FREE(queue->last);
+ FREE(queue);
+ return;
+
+} /* end of cuddLevelQueueQuit */
+
+
+/**Function********************************************************************
+
+ Synopsis [Inserts a new key in a level queue.]
+
+ Description [Inserts a new key in a level queue. A new entry is
+ created in the queue only if the node is not already
+ enqueued. Returns a pointer to the queue item if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddLevelQueueInit cuddLevelQueueDequeue]
+
+******************************************************************************/
+void *
+cuddLevelQueueEnqueue(
+ DdLevelQueue * queue /* level queue */,
+ void * key /* key to be enqueued */,
+ int level /* level at which to insert */)
+{
+ int plevel;
+ DdQueueItem *item;
+
+#ifdef DD_DEBUG
+ assert(level < queue->levels);
+#endif
+ /* Check whether entry for this node exists. */
+ item = hashLookup(queue,key);
+ if (item != NULL) return(item);
+
+ /* Get a free item from either the free list or the memory manager. */
+ if (queue->freelist == NULL) {
+ item = (DdQueueItem *) ALLOC(char, queue->itemsize);
+ if (item == NULL)
+ return(NULL);
+ } else {
+ item = queue->freelist;
+ queue->freelist = item->next;
+ }
+ /* Initialize. */
+ memset(item, 0, queue->itemsize);
+ item->key = key;
+ /* Update stats. */
+ queue->size++;
+
+ if (queue->last[level]) {
+ /* There are already items for this level in the queue. */
+ item->next = queue->last[level]->next;
+ queue->last[level]->next = item;
+ } else {
+ /* There are no items at the current level. Look for the first
+ ** non-empty level preceeding this one. */
+ plevel = level;
+ while (plevel != 0 && queue->last[plevel] == NULL)
+ plevel--;
+ if (queue->last[plevel] == NULL) {
+ /* No element precedes this one in the queue. */
+ item->next = (DdQueueItem *) queue->first;
+ queue->first = item;
+ } else {
+ item->next = queue->last[plevel]->next;
+ queue->last[plevel]->next = item;
+ }
+ }
+ queue->last[level] = item;
+
+ /* Insert entry for the key in the hash table. */
+ if (hashInsert(queue,item) == 0) {
+ return(NULL);
+ }
+ return(item);
+
+} /* end of cuddLevelQueueEnqueue */
+
+
+/**Function********************************************************************
+
+ Synopsis [Remove an item from the front of a level queue.]
+
+ Description [Remove an item from the front of a level queue.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddLevelQueueEnqueue]
+
+******************************************************************************/
+void
+cuddLevelQueueDequeue(
+ DdLevelQueue * queue,
+ int level)
+{
+ DdQueueItem *item = (DdQueueItem *) queue->first;
+
+ /* Delete from the hash table. */
+ hashDelete(queue,item);
+
+ /* Since we delete from the front, if this is the last item for
+ ** its level, there are no other items for the same level. */
+ if (queue->last[level] == item)
+ queue->last[level] = NULL;
+
+ queue->first = item->next;
+ /* Put item on the free list. */
+ item->next = queue->freelist;
+ queue->freelist = item;
+ /* Update stats. */
+ queue->size--;
+ return;
+
+} /* end of cuddLevelQueueDequeue */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Looks up a key in the hash table of a level queue.]
+
+ Description [Looks up a key in the hash table of a level queue. Returns
+ a pointer to the item with the given key if the key is found; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddLevelQueueEnqueue hashInsert]
+
+******************************************************************************/
+static DdQueueItem *
+hashLookup(
+ DdLevelQueue * queue,
+ void * key)
+{
+ int posn;
+ DdQueueItem *item;
+
+ posn = lqHash(key,queue->shift);
+ item = queue->buckets[posn];
+
+ while (item != NULL) {
+ if (item->key == key) {
+ return(item);
+ }
+ item = item->cnext;
+ }
+ return(NULL);
+
+} /* end of hashLookup */
+
+
+/**Function********************************************************************
+
+ Synopsis [Inserts an item in the hash table of a level queue.]
+
+ Description [Inserts an item in the hash table of a level queue. Returns
+ 1 if successful; 0 otherwise. No check is performed to see if an item with
+ the same key is already in the hash table.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddLevelQueueEnqueue]
+
+******************************************************************************/
+static int
+hashInsert(
+ DdLevelQueue * queue,
+ DdQueueItem * item)
+{
+ int result;
+ int posn;
+
+ if (queue->size > queue->maxsize) {
+ result = hashResize(queue);
+ if (result == 0) return(0);
+ }
+
+ posn = lqHash(item->key,queue->shift);
+ item->cnext = queue->buckets[posn];
+ queue->buckets[posn] = item;
+
+ return(1);
+
+} /* end of hashInsert */
+
+
+/**Function********************************************************************
+
+ Synopsis [Removes an item from the hash table of a level queue.]
+
+ Description [Removes an item from the hash table of a level queue.
+ Nothing is done if the item is not in the table.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddLevelQueueDequeue hashInsert]
+
+******************************************************************************/
+static void
+hashDelete(
+ DdLevelQueue * queue,
+ DdQueueItem * item)
+{
+ int posn;
+ DdQueueItem *prevItem;
+
+ posn = lqHash(item->key,queue->shift);
+ prevItem = queue->buckets[posn];
+
+ if (prevItem == NULL) return;
+ if (prevItem == item) {
+ queue->buckets[posn] = prevItem->cnext;
+ return;
+ }
+
+ while (prevItem->cnext != NULL) {
+ if (prevItem->cnext == item) {
+ prevItem->cnext = item->cnext;
+ return;
+ }
+ prevItem = prevItem->cnext;
+ }
+ return;
+
+} /* end of hashDelete */
+
+
+/**Function********************************************************************
+
+ Synopsis [Resizes the hash table of a level queue.]
+
+ Description [Resizes the hash table of a level queue. Returns 1 if
+ successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [hashInsert]
+
+******************************************************************************/
+static int
+hashResize(
+ DdLevelQueue * queue)
+{
+ int j;
+ int posn;
+ DdQueueItem *item;
+ DdQueueItem *next;
+ int numBuckets;
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ DdQueueItem **buckets;
+ DdQueueItem **oldBuckets = queue->buckets;
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+ int shift;
+ int oldNumBuckets = queue->numBuckets;
+ extern void (*MMoutOfMemory)(long);
+ void (*saveHandler)(long);
+
+ /* Compute the new size of the subtable. */
+ numBuckets = oldNumBuckets << 1;
+ saveHandler = MMoutOfMemory;
+ MMoutOfMemory = Cudd_OutOfMem;
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ buckets = queue->buckets = ALLOC(DdQueueItem *, numBuckets);
+ if (buckets == NULL) {
+ queue->maxsize <<= 1;
+ return(1);
+ }
+
+ queue->numBuckets = numBuckets;
+ shift = --(queue->shift);
+ queue->maxsize <<= 1;
+ memset(buckets, 0, numBuckets * sizeof(DdQueueItem *));
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+ for (j = 0; j < oldNumBuckets; j++) {
+ item = oldBuckets[j];
+ while (item != NULL) {
+ next = item->cnext;
+ posn = lqHash(item->key, shift);
+ item->cnext = buckets[posn];
+ buckets[posn] = item;
+ item = next;
+ }
+ }
+ FREE(oldBuckets);
+ return(1);
+
+} /* end of hashResize */
diff --git a/src/bdd/cudd/cuddLinear.c b/src/bdd/cudd/cuddLinear.c
new file mode 100644
index 00000000..cec7c255
--- /dev/null
+++ b/src/bdd/cudd/cuddLinear.c
@@ -0,0 +1,1333 @@
+/**CFile***********************************************************************
+
+ FileName [cuddLinear.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions for DD reduction by linear transformations.]
+
+ Description [ Internal procedures included in this module:
+ <ul>
+ <li> cuddLinearAndSifting()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> ddLinearUniqueCompare()
+ <li> ddLinearAndSiftingAux()
+ <li> ddLinearAndSiftingUp()
+ <li> ddLinearAndSiftingDown()
+ <li> ddLinearAndSiftingBackward()
+ <li> ddUndoMoves()
+ <li> ddUpdateInteractionMatrix()
+ <li> cuddLinearInPlace()
+ <li> cuddInitLinear()
+ <li> cuddResizeLinear()
+ <li> cuddXorLinear()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define CUDD_SWAP_MOVE 0
+#define CUDD_LINEAR_TRANSFORM_MOVE 1
+#define CUDD_INVERSE_TRANSFORM_MOVE 2
+#if SIZEOF_LONG == 8
+#define BPL 64
+#define LOGBPL 6
+#else
+#define BPL 32
+#define LOGBPL 5
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddLinear.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+static int *entry;
+
+#ifdef DD_STATS
+extern int ddTotalNumberSwapping;
+extern int ddTotalNISwaps;
+static int ddTotalNumberLinearTr;
+#endif
+
+#ifdef DD_DEBUG
+static int zero = 0;
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int ddLinearUniqueCompare ARGS((int *ptrX, int *ptrY));
+static int ddLinearAndSiftingAux ARGS((DdManager *table, int x, int xLow, int xHigh));
+static Move * ddLinearAndSiftingUp ARGS((DdManager *table, int y, int xLow, Move *prevMoves));
+static Move * ddLinearAndSiftingDown ARGS((DdManager *table, int x, int xHigh, Move *prevMoves));
+static int ddLinearAndSiftingBackward ARGS((DdManager *table, int size, Move *moves));
+static Move* ddUndoMoves ARGS((DdManager *table, Move *moves));
+static int cuddLinearInPlace ARGS((DdManager *table, int x, int y));
+static void ddUpdateInteractionMatrix ARGS((DdManager *table, int xindex, int yindex));
+static int cuddInitLinear ARGS((DdManager *table));
+static int cuddResizeLinear ARGS((DdManager *table));
+static void cuddXorLinear ARGS((DdManager *table, int x, int y));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints the linear transform matrix.]
+
+ Description [Prints the linear transform matrix. Returns 1 in case of
+ success; 0 otherwise.]
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+Cudd_PrintLinear(
+ DdManager * table)
+{
+ int i,j,k;
+ int retval;
+ int nvars = table->linearSize;
+ int wordsPerRow = ((nvars - 1) >> LOGBPL) + 1;
+ long word;
+
+ for (i = 0; i < nvars; i++) {
+ for (j = 0; j < wordsPerRow; j++) {
+ word = table->linear[i*wordsPerRow + j];
+ for (k = 0; k < BPL; k++) {
+ retval = fprintf(table->out,"%ld",word & 1);
+ if (retval == 0) return(0);
+ word >>= 1;
+ }
+ }
+ retval = fprintf(table->out,"\n");
+ if (retval == 0) return(0);
+ }
+ return(1);
+
+} /* end of Cudd_PrintLinear */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads an entry of the linear transform matrix.]
+
+ Description [Reads an entry of the linear transform matrix.]
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+Cudd_ReadLinear(
+ DdManager * table /* CUDD manager */,
+ int x /* row index */,
+ int y /* column index */)
+{
+ int nvars = table->size;
+ int wordsPerRow = ((nvars - 1) >> LOGBPL) + 1;
+ long word;
+ int bit;
+ int result;
+
+ assert(table->size == table->linearSize);
+
+ word = wordsPerRow * x + (y >> LOGBPL);
+ bit = y & (BPL-1);
+ result = (int) ((table->linear[word] >> bit) & 1);
+ return(result);
+
+} /* end of Cudd_ReadLinear */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [BDD reduction based on combination of sifting and linear
+ transformations.]
+
+ Description [BDD reduction based on combination of sifting and linear
+ transformations. Assumes that no dead nodes are present.
+ <ol>
+ <li> Order all the variables according to the number of entries
+ in each unique table.
+ <li> Sift the variable up and down, remembering each time the
+ total size of the DD heap. At each position, linear transformation
+ of the two adjacent variables is tried and is accepted if it reduces
+ the size of the DD.
+ <li> Select the best permutation.
+ <li> Repeat 3 and 4 for all variables.
+ </ol>
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+int
+cuddLinearAndSifting(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int i;
+ int *var;
+ int size;
+ int x;
+ int result;
+#ifdef DD_STATS
+ int previousSize;
+#endif
+
+#ifdef DD_STATS
+ ddTotalNumberLinearTr = 0;
+#endif
+
+ size = table->size;
+
+ var = NULL;
+ entry = NULL;
+ if (table->linear == NULL) {
+ result = cuddInitLinear(table);
+ if (result == 0) goto cuddLinearAndSiftingOutOfMem;
+#if 0
+ (void) fprintf(table->out,"\n");
+ result = Cudd_PrintLinear(table);
+ if (result == 0) goto cuddLinearAndSiftingOutOfMem;
+#endif
+ } else if (table->size != table->linearSize) {
+ result = cuddResizeLinear(table);
+ if (result == 0) goto cuddLinearAndSiftingOutOfMem;
+#if 0
+ (void) fprintf(table->out,"\n");
+ result = Cudd_PrintLinear(table);
+ if (result == 0) goto cuddLinearAndSiftingOutOfMem;
+#endif
+ }
+
+ /* Find order in which to sift variables. */
+ entry = ALLOC(int,size);
+ if (entry == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto cuddLinearAndSiftingOutOfMem;
+ }
+ var = ALLOC(int,size);
+ if (var == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto cuddLinearAndSiftingOutOfMem;
+ }
+
+ for (i = 0; i < size; i++) {
+ x = table->perm[i];
+ entry[i] = table->subtables[x].keys;
+ var[i] = i;
+ }
+
+ qsort((void *)var,size,sizeof(int),(int (*)(const void *, const void *))ddLinearUniqueCompare);
+
+ /* Now sift. */
+ for (i = 0; i < ddMin(table->siftMaxVar,size); i++) {
+ x = table->perm[var[i]];
+ if (x < lower || x > upper) continue;
+#ifdef DD_STATS
+ previousSize = table->keys - table->isolated;
+#endif
+ result = ddLinearAndSiftingAux(table,x,lower,upper);
+ if (!result) goto cuddLinearAndSiftingOutOfMem;
+#ifdef DD_STATS
+ if (table->keys < (unsigned) previousSize + table->isolated) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keys > (unsigned) previousSize + table->isolated) {
+ (void) fprintf(table->out,"+"); /* should never happen */
+ (void) fprintf(table->out,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keys - table->isolated, var[i]);
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+#ifdef DD_DEBUG
+ (void) Cudd_DebugCheck(table);
+#endif
+ }
+
+ FREE(var);
+ FREE(entry);
+
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\n#:L_LINSIFT %8d: linear trans.",
+ ddTotalNumberLinearTr);
+#endif
+
+ return(1);
+
+cuddLinearAndSiftingOutOfMem:
+
+ if (entry != NULL) FREE(entry);
+ if (var != NULL) FREE(var);
+
+ return(0);
+
+} /* end of cuddLinearAndSifting */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Comparison function used by qsort.]
+
+ Description [Comparison function used by qsort to order the
+ variables according to the number of keys in the subtables.
+ Returns the difference in number of keys between the two
+ variables being compared.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddLinearUniqueCompare(
+ int * ptrX,
+ int * ptrY)
+{
+#if 0
+ if (entry[*ptrY] == entry[*ptrX]) {
+ return((*ptrX) - (*ptrY));
+ }
+#endif
+ return(entry[*ptrY] - entry[*ptrX]);
+
+} /* end of ddLinearUniqueCompare */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given xLow <= x <= xHigh moves x up and down between the
+ boundaries.]
+
+ Description [Given xLow <= x <= xHigh moves x up and down between the
+ boundaries. At each step a linear transformation is tried, and, if it
+ decreases the size of the DD, it is accepted. Finds the best position
+ and does the required changes. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddLinearAndSiftingAux(
+ DdManager * table,
+ int x,
+ int xLow,
+ int xHigh)
+{
+
+ Move *move;
+ Move *moveUp; /* list of up moves */
+ Move *moveDown; /* list of down moves */
+ int initialSize;
+ int result;
+
+ initialSize = table->keys - table->isolated;
+
+ moveDown = NULL;
+ moveUp = NULL;
+
+ if (x == xLow) {
+ moveDown = ddLinearAndSiftingDown(table,x,xHigh,NULL);
+ /* At this point x --> xHigh unless bounding occurred. */
+ if (moveDown == (Move *) CUDD_OUT_OF_MEM) goto ddLinearAndSiftingAuxOutOfMem;
+ /* Move backward and stop at best position. */
+ result = ddLinearAndSiftingBackward(table,initialSize,moveDown);
+ if (!result) goto ddLinearAndSiftingAuxOutOfMem;
+
+ } else if (x == xHigh) {
+ moveUp = ddLinearAndSiftingUp(table,x,xLow,NULL);
+ /* At this point x --> xLow unless bounding occurred. */
+ if (moveUp == (Move *) CUDD_OUT_OF_MEM) goto ddLinearAndSiftingAuxOutOfMem;
+ /* Move backward and stop at best position. */
+ result = ddLinearAndSiftingBackward(table,initialSize,moveUp);
+ if (!result) goto ddLinearAndSiftingAuxOutOfMem;
+
+ } else if ((x - xLow) > (xHigh - x)) { /* must go down first: shorter */
+ moveDown = ddLinearAndSiftingDown(table,x,xHigh,NULL);
+ /* At this point x --> xHigh unless bounding occurred. */
+ if (moveDown == (Move *) CUDD_OUT_OF_MEM) goto ddLinearAndSiftingAuxOutOfMem;
+ moveUp = ddUndoMoves(table,moveDown);
+#ifdef DD_DEBUG
+ assert(moveUp == NULL || moveUp->x == x);
+#endif
+ moveUp = ddLinearAndSiftingUp(table,x,xLow,moveUp);
+ if (moveUp == (Move *) CUDD_OUT_OF_MEM) goto ddLinearAndSiftingAuxOutOfMem;
+ /* Move backward and stop at best position. */
+ result = ddLinearAndSiftingBackward(table,initialSize,moveUp);
+ if (!result) goto ddLinearAndSiftingAuxOutOfMem;
+
+ } else { /* must go up first: shorter */
+ moveUp = ddLinearAndSiftingUp(table,x,xLow,NULL);
+ /* At this point x --> xLow unless bounding occurred. */
+ if (moveUp == (Move *) CUDD_OUT_OF_MEM) goto ddLinearAndSiftingAuxOutOfMem;
+ moveDown = ddUndoMoves(table,moveUp);
+#ifdef DD_DEBUG
+ assert(moveDown == NULL || moveDown->y == x);
+#endif
+ moveDown = ddLinearAndSiftingDown(table,x,xHigh,moveDown);
+ if (moveDown == (Move *) CUDD_OUT_OF_MEM) goto ddLinearAndSiftingAuxOutOfMem;
+ /* Move backward and stop at best position. */
+ result = ddLinearAndSiftingBackward(table,initialSize,moveDown);
+ if (!result) goto ddLinearAndSiftingAuxOutOfMem;
+ }
+
+ while (moveDown != NULL) {
+ move = moveDown->next;
+ cuddDeallocNode(table, (DdNode *) moveDown);
+ moveDown = move;
+ }
+ while (moveUp != NULL) {
+ move = moveUp->next;
+ cuddDeallocNode(table, (DdNode *) moveUp);
+ moveUp = move;
+ }
+
+ return(1);
+
+ddLinearAndSiftingAuxOutOfMem:
+ while (moveDown != NULL) {
+ move = moveDown->next;
+ cuddDeallocNode(table, (DdNode *) moveDown);
+ moveDown = move;
+ }
+ while (moveUp != NULL) {
+ move = moveUp->next;
+ cuddDeallocNode(table, (DdNode *) moveUp);
+ moveUp = move;
+ }
+
+ return(0);
+
+} /* end of ddLinearAndSiftingAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts a variable up and applies linear transformations.]
+
+ Description [Sifts a variable up and applies linear transformations.
+ Moves y up until either it reaches the bound (xLow) or the size of
+ the DD heap increases too much. Returns the set of moves in case of
+ success; NULL if memory is full.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static Move *
+ddLinearAndSiftingUp(
+ DdManager * table,
+ int y,
+ int xLow,
+ Move * prevMoves)
+{
+ Move *moves;
+ Move *move;
+ int x;
+ int size, newsize;
+ int limitSize;
+ int xindex, yindex;
+ int isolated;
+ int L; /* lower bound on DD size */
+#ifdef DD_DEBUG
+ int checkL;
+ int z;
+ int zindex;
+#endif
+
+ moves = prevMoves;
+ yindex = table->invperm[y];
+
+ /* Initialize the lower bound.
+ ** The part of the DD below y will not change.
+ ** The part of the DD above y that does not interact with y will not
+ ** change. The rest may vanish in the best case, except for
+ ** the nodes at level xLow, which will not vanish, regardless.
+ */
+ limitSize = L = table->keys - table->isolated;
+ for (x = xLow + 1; x < y; x++) {
+ xindex = table->invperm[x];
+ if (cuddTestInteract(table,xindex,yindex)) {
+ isolated = table->vars[xindex]->ref == 1;
+ L -= table->subtables[x].keys - isolated;
+ }
+ }
+ isolated = table->vars[yindex]->ref == 1;
+ L -= table->subtables[y].keys - isolated;
+
+ x = cuddNextLow(table,y);
+ while (x >= xLow && L <= limitSize) {
+ xindex = table->invperm[x];
+#ifdef DD_DEBUG
+ checkL = table->keys - table->isolated;
+ for (z = xLow + 1; z < y; z++) {
+ zindex = table->invperm[z];
+ if (cuddTestInteract(table,zindex,yindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ checkL -= table->subtables[z].keys - isolated;
+ }
+ }
+ isolated = table->vars[yindex]->ref == 1;
+ checkL -= table->subtables[y].keys - isolated;
+ if (L != checkL) {
+ (void) fprintf(table->out, "checkL(%d) != L(%d)\n",checkL,L);
+ }
+#endif
+ size = cuddSwapInPlace(table,x,y);
+ if (size == 0) goto ddLinearAndSiftingUpOutOfMem;
+ newsize = cuddLinearInPlace(table,x,y);
+ if (newsize == 0) goto ddLinearAndSiftingUpOutOfMem;
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddLinearAndSiftingUpOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->next = moves;
+ moves = move;
+ move->flags = CUDD_SWAP_MOVE;
+ if (newsize >= size) {
+ /* Undo transformation. The transformation we apply is
+ ** its own inverse. Hence, we just apply the transformation
+ ** again.
+ */
+ newsize = cuddLinearInPlace(table,x,y);
+ if (newsize == 0) goto ddLinearAndSiftingUpOutOfMem;
+#ifdef DD_DEBUG
+ if (newsize != size) {
+ (void) fprintf(table->out,"Change in size after identity transformation! From %d to %d\n",size,newsize);
+ }
+#endif
+ } else if (cuddTestInteract(table,xindex,yindex)) {
+ size = newsize;
+ move->flags = CUDD_LINEAR_TRANSFORM_MOVE;
+ ddUpdateInteractionMatrix(table,xindex,yindex);
+ }
+ move->size = size;
+ /* Update the lower bound. */
+ if (cuddTestInteract(table,xindex,yindex)) {
+ isolated = table->vars[xindex]->ref == 1;
+ L += table->subtables[y].keys - isolated;
+ }
+ if ((double) size > (double) limitSize * table->maxGrowth) break;
+ if (size < limitSize) limitSize = size;
+ y = x;
+ x = cuddNextLow(table,y);
+ }
+ return(moves);
+
+ddLinearAndSiftingUpOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+ return((Move *) CUDD_OUT_OF_MEM);
+
+} /* end of ddLinearAndSiftingUp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts a variable down and applies linear transformations.]
+
+ Description [Sifts a variable down and applies linear
+ transformations. Moves x down until either it reaches the bound
+ (xHigh) or the size of the DD heap increases too much. Returns the
+ set of moves in case of success; NULL if memory is full.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static Move *
+ddLinearAndSiftingDown(
+ DdManager * table,
+ int x,
+ int xHigh,
+ Move * prevMoves)
+{
+ Move *moves;
+ Move *move;
+ int y;
+ int size, newsize;
+ int R; /* upper bound on node decrease */
+ int limitSize;
+ int xindex, yindex;
+ int isolated;
+#ifdef DD_DEBUG
+ int checkR;
+ int z;
+ int zindex;
+#endif
+
+ moves = prevMoves;
+ /* Initialize R */
+ xindex = table->invperm[x];
+ limitSize = size = table->keys - table->isolated;
+ R = 0;
+ for (y = xHigh; y > x; y--) {
+ yindex = table->invperm[y];
+ if (cuddTestInteract(table,xindex,yindex)) {
+ isolated = table->vars[yindex]->ref == 1;
+ R += table->subtables[y].keys - isolated;
+ }
+ }
+
+ y = cuddNextHigh(table,x);
+ while (y <= xHigh && size - R < limitSize) {
+#ifdef DD_DEBUG
+ checkR = 0;
+ for (z = xHigh; z > x; z--) {
+ zindex = table->invperm[z];
+ if (cuddTestInteract(table,xindex,zindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ checkR += table->subtables[z].keys - isolated;
+ }
+ }
+ if (R != checkR) {
+ (void) fprintf(table->out, "checkR(%d) != R(%d)\n",checkR,R);
+ }
+#endif
+ /* Update upper bound on node decrease. */
+ yindex = table->invperm[y];
+ if (cuddTestInteract(table,xindex,yindex)) {
+ isolated = table->vars[yindex]->ref == 1;
+ R -= table->subtables[y].keys - isolated;
+ }
+ size = cuddSwapInPlace(table,x,y);
+ if (size == 0) goto ddLinearAndSiftingDownOutOfMem;
+ newsize = cuddLinearInPlace(table,x,y);
+ if (newsize == 0) goto ddLinearAndSiftingDownOutOfMem;
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddLinearAndSiftingDownOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->next = moves;
+ moves = move;
+ move->flags = CUDD_SWAP_MOVE;
+ if (newsize >= size) {
+ /* Undo transformation. The transformation we apply is
+ ** its own inverse. Hence, we just apply the transformation
+ ** again.
+ */
+ newsize = cuddLinearInPlace(table,x,y);
+ if (newsize == 0) goto ddLinearAndSiftingDownOutOfMem;
+ if (newsize != size) {
+ (void) fprintf(table->out,"Change in size after identity transformation! From %d to %d\n",size,newsize);
+ }
+ } else if (cuddTestInteract(table,xindex,yindex)) {
+ size = newsize;
+ move->flags = CUDD_LINEAR_TRANSFORM_MOVE;
+ ddUpdateInteractionMatrix(table,xindex,yindex);
+ }
+ move->size = size;
+ if ((double) size > (double) limitSize * table->maxGrowth) break;
+ if (size < limitSize) limitSize = size;
+ x = y;
+ y = cuddNextHigh(table,x);
+ }
+ return(moves);
+
+ddLinearAndSiftingDownOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+ return((Move *) CUDD_OUT_OF_MEM);
+
+} /* end of ddLinearAndSiftingDown */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given a set of moves, returns the DD heap to the order
+ giving the minimum size.]
+
+ Description [Given a set of moves, returns the DD heap to the
+ position giving the minimum size. In case of ties, returns to the
+ closest position giving the minimum size. Returns 1 in case of
+ success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddLinearAndSiftingBackward(
+ DdManager * table,
+ int size,
+ Move * moves)
+{
+ Move *move;
+ int res;
+
+ for (move = moves; move != NULL; move = move->next) {
+ if (move->size < size) {
+ size = move->size;
+ }
+ }
+
+ for (move = moves; move != NULL; move = move->next) {
+ if (move->size == size) return(1);
+ if (move->flags == CUDD_LINEAR_TRANSFORM_MOVE) {
+ res = cuddLinearInPlace(table,(int)move->x,(int)move->y);
+ if (!res) return(0);
+ }
+ res = cuddSwapInPlace(table,(int)move->x,(int)move->y);
+ if (!res) return(0);
+ if (move->flags == CUDD_INVERSE_TRANSFORM_MOVE) {
+ res = cuddLinearInPlace(table,(int)move->x,(int)move->y);
+ if (!res) return(0);
+ }
+ }
+
+ return(1);
+
+} /* end of ddLinearAndSiftingBackward */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given a set of moves, returns the DD heap to the order
+ in effect before the moves.]
+
+ Description [Given a set of moves, returns the DD heap to the
+ order in effect before the moves. Returns 1 in case of success;
+ 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static Move*
+ddUndoMoves(
+ DdManager * table,
+ Move * moves)
+{
+ Move *invmoves = NULL;
+ Move *move;
+ Move *invmove;
+ int size;
+
+ for (move = moves; move != NULL; move = move->next) {
+ invmove = (Move *) cuddDynamicAllocNode(table);
+ if (invmove == NULL) goto ddUndoMovesOutOfMem;
+ invmove->x = move->x;
+ invmove->y = move->y;
+ invmove->next = invmoves;
+ invmoves = invmove;
+ if (move->flags == CUDD_SWAP_MOVE) {
+ invmove->flags = CUDD_SWAP_MOVE;
+ size = cuddSwapInPlace(table,(int)move->x,(int)move->y);
+ if (!size) goto ddUndoMovesOutOfMem;
+ } else if (move->flags == CUDD_LINEAR_TRANSFORM_MOVE) {
+ invmove->flags = CUDD_INVERSE_TRANSFORM_MOVE;
+ size = cuddLinearInPlace(table,(int)move->x,(int)move->y);
+ if (!size) goto ddUndoMovesOutOfMem;
+ size = cuddSwapInPlace(table,(int)move->x,(int)move->y);
+ if (!size) goto ddUndoMovesOutOfMem;
+ } else { /* must be CUDD_INVERSE_TRANSFORM_MOVE */
+#ifdef DD_DEBUG
+ (void) fprintf(table->err,"Unforseen event in ddUndoMoves!\n");
+#endif
+ invmove->flags = CUDD_LINEAR_TRANSFORM_MOVE;
+ size = cuddSwapInPlace(table,(int)move->x,(int)move->y);
+ if (!size) goto ddUndoMovesOutOfMem;
+ size = cuddLinearInPlace(table,(int)move->x,(int)move->y);
+ if (!size) goto ddUndoMovesOutOfMem;
+ }
+ invmove->size = size;
+ }
+
+ return(invmoves);
+
+ddUndoMovesOutOfMem:
+ while (invmoves != NULL) {
+ move = invmoves->next;
+ cuddDeallocNode(table, (DdNode *) invmoves);
+ invmoves = move;
+ }
+ return((Move *) CUDD_OUT_OF_MEM);
+
+} /* end of ddUndoMoves */
+
+
+/**Function********************************************************************
+
+ Synopsis [Linearly combines two adjacent variables.]
+
+ Description [Linearly combines two adjacent variables. Specifically,
+ replaces the top variable with the exclusive nor of the two variables.
+ It assumes that no dead nodes are present on entry to this
+ procedure. The procedure then guarantees that no dead nodes will be
+ present when it terminates. cuddLinearInPlace assumes that x &lt;
+ y. Returns the number of keys in the table if successful; 0
+ otherwise.]
+
+ SideEffects [The two subtables corrresponding to variables x and y are
+ modified. The global counters of the unique table are also affected.]
+
+ SeeAlso [cuddSwapInPlace]
+
+******************************************************************************/
+static int
+cuddLinearInPlace(
+ DdManager * table,
+ int x,
+ int y)
+{
+ DdNodePtr *xlist, *ylist;
+ int xindex, yindex;
+ int xslots, yslots;
+ int xshift, yshift;
+ int oldxkeys, oldykeys;
+ int newxkeys, newykeys;
+ int comple, newcomplement;
+ int i;
+ int posn;
+ int isolated;
+ DdNode *f,*f0,*f1,*f01,*f00,*f11,*f10,*newf1,*newf0;
+ DdNode *g,*next,*last;
+ DdNodePtr *previousP;
+ DdNode *tmp;
+ DdNode *sentinel = &(table->sentinel);
+#if DD_DEBUG
+ int count, idcheck;
+#endif
+
+#ifdef DD_DEBUG
+ assert(x < y);
+ assert(cuddNextHigh(table,x) == y);
+ assert(table->subtables[x].keys != 0);
+ assert(table->subtables[y].keys != 0);
+ assert(table->subtables[x].dead == 0);
+ assert(table->subtables[y].dead == 0);
+#endif
+
+ xindex = table->invperm[x];
+ yindex = table->invperm[y];
+
+ if (cuddTestInteract(table,xindex,yindex)) {
+#ifdef DD_STATS
+ ddTotalNumberLinearTr++;
+#endif
+ /* Get parameters of x subtable. */
+ xlist = table->subtables[x].nodelist;
+ oldxkeys = table->subtables[x].keys;
+ xslots = table->subtables[x].slots;
+ xshift = table->subtables[x].shift;
+
+ /* Get parameters of y subtable. */
+ ylist = table->subtables[y].nodelist;
+ oldykeys = table->subtables[y].keys;
+ yslots = table->subtables[y].slots;
+ yshift = table->subtables[y].shift;
+
+ newxkeys = 0;
+ newykeys = oldykeys;
+
+ /* Check whether the two projection functions involved in this
+ ** swap are isolated. At the end, we'll be able to tell how many
+ ** isolated projection functions are there by checking only these
+ ** two functions again. This is done to eliminate the isolated
+ ** projection functions from the node count.
+ */
+ isolated = - ((table->vars[xindex]->ref == 1) +
+ (table->vars[yindex]->ref == 1));
+
+ /* The nodes in the x layer are put in a chain.
+ ** The chain is handled as a FIFO; g points to the beginning and
+ ** last points to the end.
+ */
+ g = NULL;
+ for (i = 0; i < xslots; i++) {
+ f = xlist[i];
+ if (f == sentinel) continue;
+ xlist[i] = sentinel;
+ if (g == NULL) {
+ g = f;
+ } else {
+ last->next = f;
+ }
+ while ((next = f->next) != sentinel) {
+ f = next;
+ } /* while there are elements in the collision chain */
+ last = f;
+ } /* for each slot of the x subtable */
+ last->next = NULL;
+
+#ifdef DD_COUNT
+ table->swapSteps += oldxkeys;
+#endif
+ /* Take care of the x nodes that must be re-expressed.
+ ** They form a linked list pointed by g.
+ */
+ f = g;
+ while (f != NULL) {
+ next = f->next;
+ /* Find f1, f0, f11, f10, f01, f00. */
+ f1 = cuddT(f);
+#ifdef DD_DEBUG
+ assert(!(Cudd_IsComplement(f1)));
+#endif
+ if ((int) f1->index == yindex) {
+ f11 = cuddT(f1); f10 = cuddE(f1);
+ } else {
+ f11 = f10 = f1;
+ }
+#ifdef DD_DEBUG
+ assert(!(Cudd_IsComplement(f11)));
+#endif
+ f0 = cuddE(f);
+ comple = Cudd_IsComplement(f0);
+ f0 = Cudd_Regular(f0);
+ if ((int) f0->index == yindex) {
+ f01 = cuddT(f0); f00 = cuddE(f0);
+ } else {
+ f01 = f00 = f0;
+ }
+ if (comple) {
+ f01 = Cudd_Not(f01);
+ f00 = Cudd_Not(f00);
+ }
+ /* Decrease ref count of f1. */
+ cuddSatDec(f1->ref);
+ /* Create the new T child. */
+ if (f11 == f00) {
+ newf1 = f11;
+ cuddSatInc(newf1->ref);
+ } else {
+ /* Check ylist for triple (yindex,f11,f00). */
+ posn = ddHash(f11, f00, yshift);
+ /* For each element newf1 in collision list ylist[posn]. */
+ previousP = &(ylist[posn]);
+ newf1 = *previousP;
+ while (f11 < cuddT(newf1)) {
+ previousP = &(newf1->next);
+ newf1 = *previousP;
+ }
+ while (f11 == cuddT(newf1) && f00 < cuddE(newf1)) {
+ previousP = &(newf1->next);
+ newf1 = *previousP;
+ }
+ if (cuddT(newf1) == f11 && cuddE(newf1) == f00) {
+ cuddSatInc(newf1->ref);
+ } else { /* no match */
+ newf1 = cuddDynamicAllocNode(table);
+ if (newf1 == NULL)
+ goto cuddLinearOutOfMem;
+ newf1->index = yindex; newf1->ref = 1;
+ cuddT(newf1) = f11;
+ cuddE(newf1) = f00;
+ /* Insert newf1 in the collision list ylist[posn];
+ ** increase the ref counts of f11 and f00.
+ */
+ newykeys++;
+ newf1->next = *previousP;
+ *previousP = newf1;
+ cuddSatInc(f11->ref);
+ tmp = Cudd_Regular(f00);
+ cuddSatInc(tmp->ref);
+ }
+ }
+ cuddT(f) = newf1;
+#ifdef DD_DEBUG
+ assert(!(Cudd_IsComplement(newf1)));
+#endif
+
+ /* Do the same for f0, keeping complement dots into account. */
+ /* decrease ref count of f0 */
+ tmp = Cudd_Regular(f0);
+ cuddSatDec(tmp->ref);
+ /* create the new E child */
+ if (f01 == f10) {
+ newf0 = f01;
+ tmp = Cudd_Regular(newf0);
+ cuddSatInc(tmp->ref);
+ } else {
+ /* make sure f01 is regular */
+ newcomplement = Cudd_IsComplement(f01);
+ if (newcomplement) {
+ f01 = Cudd_Not(f01);
+ f10 = Cudd_Not(f10);
+ }
+ /* Check ylist for triple (yindex,f01,f10). */
+ posn = ddHash(f01, f10, yshift);
+ /* For each element newf0 in collision list ylist[posn]. */
+ previousP = &(ylist[posn]);
+ newf0 = *previousP;
+ while (f01 < cuddT(newf0)) {
+ previousP = &(newf0->next);
+ newf0 = *previousP;
+ }
+ while (f01 == cuddT(newf0) && f10 < cuddE(newf0)) {
+ previousP = &(newf0->next);
+ newf0 = *previousP;
+ }
+ if (cuddT(newf0) == f01 && cuddE(newf0) == f10) {
+ cuddSatInc(newf0->ref);
+ } else { /* no match */
+ newf0 = cuddDynamicAllocNode(table);
+ if (newf0 == NULL)
+ goto cuddLinearOutOfMem;
+ newf0->index = yindex; newf0->ref = 1;
+ cuddT(newf0) = f01;
+ cuddE(newf0) = f10;
+ /* Insert newf0 in the collision list ylist[posn];
+ ** increase the ref counts of f01 and f10.
+ */
+ newykeys++;
+ newf0->next = *previousP;
+ *previousP = newf0;
+ cuddSatInc(f01->ref);
+ tmp = Cudd_Regular(f10);
+ cuddSatInc(tmp->ref);
+ }
+ if (newcomplement) {
+ newf0 = Cudd_Not(newf0);
+ }
+ }
+ cuddE(f) = newf0;
+
+ /* Re-insert the modified f in xlist.
+ ** The modified f does not already exists in xlist.
+ ** (Because of the uniqueness of the cofactors.)
+ */
+ posn = ddHash(newf1, newf0, xshift);
+ newxkeys++;
+ previousP = &(xlist[posn]);
+ tmp = *previousP;
+ while (newf1 < cuddT(tmp)) {
+ previousP = &(tmp->next);
+ tmp = *previousP;
+ }
+ while (newf1 == cuddT(tmp) && newf0 < cuddE(tmp)) {
+ previousP = &(tmp->next);
+ tmp = *previousP;
+ }
+ f->next = *previousP;
+ *previousP = f;
+ f = next;
+ } /* while f != NULL */
+
+ /* GC the y layer. */
+
+ /* For each node f in ylist. */
+ for (i = 0; i < yslots; i++) {
+ previousP = &(ylist[i]);
+ f = *previousP;
+ while (f != sentinel) {
+ next = f->next;
+ if (f->ref == 0) {
+ tmp = cuddT(f);
+ cuddSatDec(tmp->ref);
+ tmp = Cudd_Regular(cuddE(f));
+ cuddSatDec(tmp->ref);
+ cuddDeallocNode(table,f);
+ newykeys--;
+ } else {
+ *previousP = f;
+ previousP = &(f->next);
+ }
+ f = next;
+ } /* while f */
+ *previousP = sentinel;
+ } /* for every collision list */
+
+#if DD_DEBUG
+#if 0
+ (void) fprintf(table->out,"Linearly combining %d and %d\n",x,y);
+#endif
+ count = 0;
+ idcheck = 0;
+ for (i = 0; i < yslots; i++) {
+ f = ylist[i];
+ while (f != sentinel) {
+ count++;
+ if (f->index != (DdHalfWord) yindex)
+ idcheck++;
+ f = f->next;
+ }
+ }
+ if (count != newykeys) {
+ fprintf(table->err,"Error in finding newykeys\toldykeys = %d\tnewykeys = %d\tactual = %d\n",oldykeys,newykeys,count);
+ }
+ if (idcheck != 0)
+ fprintf(table->err,"Error in id's of ylist\twrong id's = %d\n",idcheck);
+ count = 0;
+ idcheck = 0;
+ for (i = 0; i < xslots; i++) {
+ f = xlist[i];
+ while (f != sentinel) {
+ count++;
+ if (f->index != (DdHalfWord) xindex)
+ idcheck++;
+ f = f->next;
+ }
+ }
+ if (count != newxkeys || newxkeys != oldxkeys) {
+ fprintf(table->err,"Error in finding newxkeys\toldxkeys = %d \tnewxkeys = %d \tactual = %d\n",oldxkeys,newxkeys,count);
+ }
+ if (idcheck != 0)
+ fprintf(table->err,"Error in id's of xlist\twrong id's = %d\n",idcheck);
+#endif
+
+ isolated += (table->vars[xindex]->ref == 1) +
+ (table->vars[yindex]->ref == 1);
+ table->isolated += isolated;
+
+ /* Set the appropriate fields in table. */
+ table->subtables[y].keys = newykeys;
+
+ /* Here we should update the linear combination table
+ ** to record that x <- x EXNOR y. This is done by complementing
+ ** the (x,y) entry of the table.
+ */
+
+ table->keys += newykeys - oldykeys;
+
+ cuddXorLinear(table,xindex,yindex);
+ }
+
+#ifdef DD_DEBUG
+ if (zero) {
+ (void) Cudd_DebugCheck(table);
+ }
+#endif
+
+ return(table->keys - table->isolated);
+
+cuddLinearOutOfMem:
+ (void) fprintf(table->err,"Error: cuddLinearInPlace out of memory\n");
+
+ return (0);
+
+} /* end of cuddLinearInPlace */
+
+
+/**Function********************************************************************
+
+ Synopsis [Updates the interaction matrix.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+ddUpdateInteractionMatrix(
+ DdManager * table,
+ int xindex,
+ int yindex)
+{
+ int i;
+ for (i = 0; i < yindex; i++) {
+ if (i != xindex && cuddTestInteract(table,i,yindex)) {
+ if (i < xindex) {
+ cuddSetInteract(table,i,xindex);
+ } else {
+ cuddSetInteract(table,xindex,i);
+ }
+ }
+ }
+ for (i = yindex+1; i < table->size; i++) {
+ if (i != xindex && cuddTestInteract(table,yindex,i)) {
+ if (i < xindex) {
+ cuddSetInteract(table,i,xindex);
+ } else {
+ cuddSetInteract(table,xindex,i);
+ }
+ }
+ }
+
+} /* end of ddUpdateInteractionMatrix */
+
+
+/**Function********************************************************************
+
+ Synopsis [Initializes the linear transform matrix.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddInitLinear(
+ DdManager * table)
+{
+ int words;
+ int wordsPerRow;
+ int nvars;
+ int word;
+ int bit;
+ int i;
+ long *linear;
+
+ nvars = table->size;
+ wordsPerRow = ((nvars - 1) >> LOGBPL) + 1;
+ words = wordsPerRow * nvars;
+ table->linear = linear = ALLOC(long,words);
+ if (linear == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ table->memused += words * sizeof(long);
+ table->linearSize = nvars;
+ for (i = 0; i < words; i++) linear[i] = 0;
+ for (i = 0; i < nvars; i++) {
+ word = wordsPerRow * i + (i >> LOGBPL);
+ bit = i & (BPL-1);
+ linear[word] = 1 << bit;
+ }
+ return(1);
+
+} /* end of cuddInitLinear */
+
+
+/**Function********************************************************************
+
+ Synopsis [Resizes the linear transform matrix.]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddResizeLinear(
+ DdManager * table)
+{
+ int words,oldWords;
+ int wordsPerRow,oldWordsPerRow;
+ int nvars,oldNvars;
+ int word,oldWord;
+ int bit;
+ int i,j;
+ long *linear,*oldLinear;
+
+ oldNvars = table->linearSize;
+ oldWordsPerRow = ((oldNvars - 1) >> LOGBPL) + 1;
+ oldWords = oldWordsPerRow * oldNvars;
+ oldLinear = table->linear;
+
+ nvars = table->size;
+ wordsPerRow = ((nvars - 1) >> LOGBPL) + 1;
+ words = wordsPerRow * nvars;
+ table->linear = linear = ALLOC(long,words);
+ if (linear == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ table->memused += (words - oldWords) * sizeof(long);
+ for (i = 0; i < words; i++) linear[i] = 0;
+
+ /* Copy old matrix. */
+ for (i = 0; i < oldNvars; i++) {
+ for (j = 0; j < oldWordsPerRow; j++) {
+ oldWord = oldWordsPerRow * i + j;
+ word = wordsPerRow * i + j;
+ linear[word] = oldLinear[oldWord];
+ }
+ }
+ FREE(oldLinear);
+
+ /* Add elements to the diagonal. */
+ for (i = oldNvars; i < nvars; i++) {
+ word = wordsPerRow * i + (i >> LOGBPL);
+ bit = i & (BPL-1);
+ linear[word] = 1 << bit;
+ }
+ table->linearSize = nvars;
+
+ return(1);
+
+} /* end of cuddResizeLinear */
+
+
+/**Function********************************************************************
+
+ Synopsis [XORs two rows of the linear transform matrix.]
+
+ Description [XORs two rows of the linear transform matrix and replaces
+ the first row with the result.]
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+cuddXorLinear(
+ DdManager * table,
+ int x,
+ int y)
+{
+ int i;
+ int nvars = table->size;
+ int wordsPerRow = ((nvars - 1) >> LOGBPL) + 1;
+ int xstart = wordsPerRow * x;
+ int ystart = wordsPerRow * y;
+ long *linear = table->linear;
+
+ for (i = 0; i < wordsPerRow; i++) {
+ linear[xstart+i] ^= linear[ystart+i];
+ }
+
+} /* end of cuddXorLinear */
+
diff --git a/src/bdd/cudd/cuddLiteral.c b/src/bdd/cudd/cuddLiteral.c
new file mode 100644
index 00000000..69594486
--- /dev/null
+++ b/src/bdd/cudd/cuddLiteral.c
@@ -0,0 +1,237 @@
+/**CFile***********************************************************************
+
+ FileName [cuddLiteral.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions for manipulation of literal sets represented by
+ BDDs.]
+
+ Description [External procedures included in this file:
+ <ul>
+ <li> Cudd_bddLiteralSetIntersection()
+ </ul>
+ Internal procedures included in this file:
+ <ul>
+ <li> cuddBddLiteralSetIntersectionRecur()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddLiteral.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the intesection of two sets of literals
+ represented as BDDs.]
+
+ Description [Computes the intesection of two sets of literals
+ represented as BDDs. Each set is represented as a cube of the
+ literals in the set. The empty set is represented by the constant 1.
+ No variable can be simultaneously present in both phases in a set.
+ Returns a pointer to the BDD representing the intersected sets, if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+DdNode *
+Cudd_bddLiteralSetIntersection(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddLiteralSetIntersectionRecur(dd,f,g);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddLiteralSetIntersection */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of
+ Cudd_bddLiteralSetIntersection.]
+
+ Description [Performs the recursive step of
+ Cudd_bddLiteralSetIntersection. Scans the cubes for common variables,
+ and checks whether they agree in phase. Returns a pointer to the
+ resulting cube if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+DdNode *
+cuddBddLiteralSetIntersectionRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res, *tmp;
+ DdNode *F, *G;
+ DdNode *fc, *gc;
+ DdNode *one;
+ DdNode *zero;
+ unsigned int topf, topg, comple;
+ int phasef, phaseg;
+
+ statLine(dd);
+ if (f == g) return(f);
+
+ F = Cudd_Regular(f);
+ G = Cudd_Regular(g);
+ one = DD_ONE(dd);
+
+ /* Here f != g. If F == G, then f and g are complementary.
+ ** Since they are two cubes, this case only occurs when f == v,
+ ** g == v', and v is a variable or its complement.
+ */
+ if (F == G) return(one);
+
+ zero = Cudd_Not(one);
+ topf = cuddI(dd,F->index);
+ topg = cuddI(dd,G->index);
+ /* Look for a variable common to both cubes. If there are none, this
+ ** loop will stop when the constant node is reached in both cubes.
+ */
+ while (topf != topg) {
+ if (topf < topg) { /* move down on f */
+ comple = f != F;
+ f = cuddT(F);
+ if (comple) f = Cudd_Not(f);
+ if (f == zero) {
+ f = cuddE(F);
+ if (comple) f = Cudd_Not(f);
+ }
+ F = Cudd_Regular(f);
+ topf = cuddI(dd,F->index);
+ } else if (topg < topf) {
+ comple = g != G;
+ g = cuddT(G);
+ if (comple) g = Cudd_Not(g);
+ if (g == zero) {
+ g = cuddE(G);
+ if (comple) g = Cudd_Not(g);
+ }
+ G = Cudd_Regular(g);
+ topg = cuddI(dd,G->index);
+ }
+ }
+
+ /* At this point, f == one <=> g == 1. It suffices to test one of them. */
+ if (f == one) return(one);
+
+ res = cuddCacheLookup2(dd,Cudd_bddLiteralSetIntersection,f,g);
+ if (res != NULL) {
+ return(res);
+ }
+
+ /* Here f and g are both non constant and have the same top variable. */
+ comple = f != F;
+ fc = cuddT(F);
+ phasef = 1;
+ if (comple) fc = Cudd_Not(fc);
+ if (fc == zero) {
+ fc = cuddE(F);
+ phasef = 0;
+ if (comple) fc = Cudd_Not(fc);
+ }
+ comple = g != G;
+ gc = cuddT(G);
+ phaseg = 1;
+ if (comple) gc = Cudd_Not(gc);
+ if (gc == zero) {
+ gc = cuddE(G);
+ phaseg = 0;
+ if (comple) gc = Cudd_Not(gc);
+ }
+
+ tmp = cuddBddLiteralSetIntersectionRecur(dd,fc,gc);
+ if (tmp == NULL) {
+ return(NULL);
+ }
+
+ if (phasef != phaseg) {
+ res = tmp;
+ } else {
+ cuddRef(tmp);
+ if (phasef == 0) {
+ res = cuddBddAndRecur(dd,Cudd_Not(dd->vars[F->index]),tmp);
+ } else {
+ res = cuddBddAndRecur(dd,dd->vars[F->index],tmp);
+ }
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd,tmp);
+ return(NULL);
+ }
+ cuddDeref(tmp); /* Just cuddDeref, because it is included in result */
+ }
+
+ cuddCacheInsert2(dd,Cudd_bddLiteralSetIntersection,f,g,res);
+
+ return(res);
+
+} /* end of cuddBddLiteralSetIntersectionRecur */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
diff --git a/src/bdd/cudd/cuddMatMult.c b/src/bdd/cudd/cuddMatMult.c
new file mode 100644
index 00000000..b10975ec
--- /dev/null
+++ b/src/bdd/cudd/cuddMatMult.c
@@ -0,0 +1,680 @@
+/**CFile***********************************************************************
+
+ FileName [cuddMatMult.c]
+
+ PackageName [cudd]
+
+ Synopsis [Matrix multiplication functions.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_addMatrixMultiply()
+ <li> Cudd_addTimesPlus()
+ <li> Cudd_addTriangle()
+ <li> Cudd_addOuterSum()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> addMMRecur()
+ <li> addTriangleRecur()
+ <li> cuddAddOuterSumRecur()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddMatMult.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static DdNode * addMMRecur ARGS((DdManager *dd, DdNode *A, DdNode *B, int topP, int *vars));
+static DdNode * addTriangleRecur ARGS((DdManager *dd, DdNode *f, DdNode *g, int *vars, DdNode *cube));
+static DdNode * cuddAddOuterSumRecur ARGS((DdManager *dd, DdNode *M, DdNode *r, DdNode *c));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Calculates the product of two matrices represented as
+ ADDs.]
+
+ Description [Calculates the product of two matrices, A and B,
+ represented as ADDs. This procedure implements the quasiring multiplication
+ algorithm. A is assumed to depend on variables x (rows) and z
+ (columns). B is assumed to depend on variables z (rows) and y
+ (columns). The product of A and B then depends on x (rows) and y
+ (columns). Only the z variables have to be explicitly identified;
+ they are the "summation" variables. Returns a pointer to the
+ result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addTimesPlus Cudd_addTriangle Cudd_bddAndAbstract]
+
+******************************************************************************/
+DdNode *
+Cudd_addMatrixMultiply(
+ DdManager * dd,
+ DdNode * A,
+ DdNode * B,
+ DdNode ** z,
+ int nz)
+{
+ int i, nvars, *vars;
+ DdNode *res;
+
+ /* Array vars says what variables are "summation" variables. */
+ nvars = dd->size;
+ vars = ALLOC(int,nvars);
+ if (vars == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < nvars; i++) {
+ vars[i] = 0;
+ }
+ for (i = 0; i < nz; i++) {
+ vars[z[i]->index] = 1;
+ }
+
+ do {
+ dd->reordered = 0;
+ res = addMMRecur(dd,A,B,-1,vars);
+ } while (dd->reordered == 1);
+ FREE(vars);
+ return(res);
+
+} /* end of Cudd_addMatrixMultiply */
+
+
+/**Function********************************************************************
+
+ Synopsis [Calculates the product of two matrices represented as
+ ADDs.]
+
+ Description [Calculates the product of two matrices, A and B,
+ represented as ADDs, using the CMU matrix by matrix multiplication
+ procedure by Clarke et al.. Matrix A has x's as row variables and z's
+ as column variables, while matrix B has z's as row variables and y's
+ as column variables. Returns the pointer to the result if successful;
+ NULL otherwise. The resulting matrix has x's as row variables and y's
+ as column variables.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addMatrixMultiply]
+
+******************************************************************************/
+DdNode *
+Cudd_addTimesPlus(
+ DdManager * dd,
+ DdNode * A,
+ DdNode * B,
+ DdNode ** z,
+ int nz)
+{
+ DdNode *w, *cube, *tmp, *res;
+ int i;
+ tmp = Cudd_addApply(dd,Cudd_addTimes,A,B);
+ if (tmp == NULL) return(NULL);
+ Cudd_Ref(tmp);
+ Cudd_Ref(cube = DD_ONE(dd));
+ for (i = nz-1; i >= 0; i--) {
+ w = Cudd_addIte(dd,z[i],cube,DD_ZERO(dd));
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd,tmp);
+ return(NULL);
+ }
+ Cudd_Ref(w);
+ Cudd_RecursiveDeref(dd,cube);
+ cube = w;
+ }
+ res = Cudd_addExistAbstract(dd,tmp,cube);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd,tmp);
+ Cudd_RecursiveDeref(dd,cube);
+ return(NULL);
+ }
+ Cudd_Ref(res);
+ Cudd_RecursiveDeref(dd,cube);
+ Cudd_RecursiveDeref(dd,tmp);
+ Cudd_Deref(res);
+ return(res);
+
+} /* end of Cudd_addTimesPlus */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the triangulation step for the shortest path
+ computation.]
+
+ Description [Implements the semiring multiplication algorithm used in
+ the triangulation step for the shortest path computation. f
+ is assumed to depend on variables x (rows) and z (columns). g is
+ assumed to depend on variables z (rows) and y (columns). The product
+ of f and g then depends on x (rows) and y (columns). Only the z
+ variables have to be explicitly identified; they are the
+ "abstraction" variables. Returns a pointer to the result if
+ successful; NULL otherwise. ]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addMatrixMultiply Cudd_bddAndAbstract]
+
+******************************************************************************/
+DdNode *
+Cudd_addTriangle(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ DdNode ** z,
+ int nz)
+{
+ int i, nvars, *vars;
+ DdNode *res, *cube;
+
+ nvars = dd->size;
+ vars = ALLOC(int, nvars);
+ if (vars == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < nvars; i++) vars[i] = -1;
+ for (i = 0; i < nz; i++) vars[z[i]->index] = i;
+ cube = Cudd_addComputeCube(dd, z, NULL, nz);
+ if (cube == NULL) {
+ FREE(vars);
+ return(NULL);
+ }
+ cuddRef(cube);
+
+ do {
+ dd->reordered = 0;
+ res = addTriangleRecur(dd, f, g, vars, cube);
+ } while (dd->reordered == 1);
+ if (res != NULL) cuddRef(res);
+ Cudd_RecursiveDeref(dd,cube);
+ if (res != NULL) cuddDeref(res);
+ FREE(vars);
+ return(res);
+
+} /* end of Cudd_addTriangle */
+
+
+/**Function********************************************************************
+
+ Synopsis [Takes the minimum of a matrix and the outer sum of two vectors.]
+
+ Description [Takes the pointwise minimum of a matrix and the outer
+ sum of two vectors. This procedure is used in the Floyd-Warshall
+ all-pair shortest path algorithm. Returns a pointer to the result if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_addOuterSum(
+ DdManager *dd,
+ DdNode *M,
+ DdNode *r,
+ DdNode *c)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddAddOuterSumRecur(dd, M, r, c);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_addOuterSum */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addMatrixMultiply.]
+
+ Description [Performs the recursive step of Cudd_addMatrixMultiply.
+ Returns a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static DdNode *
+addMMRecur(
+ DdManager * dd,
+ DdNode * A,
+ DdNode * B,
+ int topP,
+ int * vars)
+{
+ DdNode *zero,
+ *At, /* positive cofactor of first operand */
+ *Ae, /* negative cofactor of first operand */
+ *Bt, /* positive cofactor of second operand */
+ *Be, /* negative cofactor of second operand */
+ *t, /* positive cofactor of result */
+ *e, /* negative cofactor of result */
+ *scaled, /* scaled result */
+ *add_scale, /* ADD representing the scaling factor */
+ *res;
+ int i; /* loop index */
+ double scale; /* scaling factor */
+ int index; /* index of the top variable */
+ CUDD_VALUE_TYPE value;
+ unsigned int topA, topB, topV;
+ DdNode *(*cacheOp)(DdManager *, DdNode *, DdNode *);
+
+ statLine(dd);
+ zero = DD_ZERO(dd);
+
+ if (A == zero || B == zero) {
+ return(zero);
+ }
+
+ if (cuddIsConstant(A) && cuddIsConstant(B)) {
+ /* Compute the scaling factor. It is 2^k, where k is the
+ ** number of summation variables below the current variable.
+ ** Indeed, these constants represent blocks of 2^k identical
+ ** constant values in both A and B.
+ */
+ value = cuddV(A) * cuddV(B);
+ for (i = 0; i < dd->size; i++) {
+ if (vars[i]) {
+ if (dd->perm[i] > topP) {
+ value *= (CUDD_VALUE_TYPE) 2;
+ }
+ }
+ }
+ res = cuddUniqueConst(dd, value);
+ return(res);
+ }
+
+ /* Standardize to increase cache efficiency. Clearly, A*B != B*A
+ ** in matrix multiplication. However, which matrix is which is
+ ** determined by the variables appearing in the ADDs and not by
+ ** which one is passed as first argument.
+ */
+ if (A > B) {
+ DdNode *tmp = A;
+ A = B;
+ B = tmp;
+ }
+
+ topA = cuddI(dd,A->index); topB = cuddI(dd,B->index);
+ topV = ddMin(topA,topB);
+
+ cacheOp = (DdNode *(*)(DdManager *, DdNode *, DdNode *)) addMMRecur;
+ res = cuddCacheLookup2(dd,cacheOp,A,B);
+ if (res != NULL) {
+ /* If the result is 0, there is no need to normalize.
+ ** Otherwise we count the number of z variables between
+ ** the current depth and the top of the ADDs. These are
+ ** the missing variables that determine the size of the
+ ** constant blocks.
+ */
+ if (res == zero) return(res);
+ scale = 1.0;
+ for (i = 0; i < dd->size; i++) {
+ if (vars[i]) {
+ if (dd->perm[i] > topP && (unsigned) dd->perm[i] < topV) {
+ scale *= 2;
+ }
+ }
+ }
+ if (scale > 1.0) {
+ cuddRef(res);
+ add_scale = cuddUniqueConst(dd,(CUDD_VALUE_TYPE)scale);
+ if (add_scale == NULL) {
+ Cudd_RecursiveDeref(dd, res);
+ return(NULL);
+ }
+ cuddRef(add_scale);
+ scaled = cuddAddApplyRecur(dd,Cudd_addTimes,res,add_scale);
+ if (scaled == NULL) {
+ Cudd_RecursiveDeref(dd, add_scale);
+ Cudd_RecursiveDeref(dd, res);
+ return(NULL);
+ }
+ cuddRef(scaled);
+ Cudd_RecursiveDeref(dd, add_scale);
+ Cudd_RecursiveDeref(dd, res);
+ res = scaled;
+ cuddDeref(res);
+ }
+ return(res);
+ }
+
+ /* compute the cofactors */
+ if (topV == topA) {
+ At = cuddT(A);
+ Ae = cuddE(A);
+ } else {
+ At = Ae = A;
+ }
+ if (topV == topB) {
+ Bt = cuddT(B);
+ Be = cuddE(B);
+ } else {
+ Bt = Be = B;
+ }
+
+ t = addMMRecur(dd, At, Bt, (int)topV, vars);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ e = addMMRecur(dd, Ae, Be, (int)topV, vars);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ index = dd->invperm[topV];
+ if (vars[index] == 0) {
+ /* We have split on either the rows of A or the columns
+ ** of B. We just need to connect the two subresults,
+ ** which correspond to two submatrices of the result.
+ */
+ res = (t == e) ? t : cuddUniqueInter(dd,index,t,e);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ Cudd_RecursiveDeref(dd, e);
+ return(NULL);
+ }
+ cuddRef(res);
+ cuddDeref(t);
+ cuddDeref(e);
+ } else {
+ /* we have simultaneously split on the columns of A and
+ ** the rows of B. The two subresults must be added.
+ */
+ res = cuddAddApplyRecur(dd,Cudd_addPlus,t,e);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ Cudd_RecursiveDeref(dd, e);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd, t);
+ Cudd_RecursiveDeref(dd, e);
+ }
+
+ cuddCacheInsert2(dd,cacheOp,A,B,res);
+
+ /* We have computed (and stored in the computed table) a minimal
+ ** result; that is, a result that assumes no summation variables
+ ** between the current depth of the recursion and its top
+ ** variable. We now take into account the z variables by properly
+ ** scaling the result.
+ */
+ if (res != zero) {
+ scale = 1.0;
+ for (i = 0; i < dd->size; i++) {
+ if (vars[i]) {
+ if (dd->perm[i] > topP && (unsigned) dd->perm[i] < topV) {
+ scale *= 2;
+ }
+ }
+ }
+ if (scale > 1.0) {
+ add_scale = cuddUniqueConst(dd,(CUDD_VALUE_TYPE)scale);
+ if (add_scale == NULL) {
+ Cudd_RecursiveDeref(dd, res);
+ return(NULL);
+ }
+ cuddRef(add_scale);
+ scaled = cuddAddApplyRecur(dd,Cudd_addTimes,res,add_scale);
+ if (scaled == NULL) {
+ Cudd_RecursiveDeref(dd, res);
+ Cudd_RecursiveDeref(dd, add_scale);
+ return(NULL);
+ }
+ cuddRef(scaled);
+ Cudd_RecursiveDeref(dd, add_scale);
+ Cudd_RecursiveDeref(dd, res);
+ res = scaled;
+ }
+ }
+ cuddDeref(res);
+ return(res);
+
+} /* end of addMMRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addTriangle.]
+
+ Description [Performs the recursive step of Cudd_addTriangle. Returns
+ a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static DdNode *
+addTriangleRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ int * vars,
+ DdNode *cube)
+{
+ DdNode *fv, *fvn, *gv, *gvn, *t, *e, *res;
+ CUDD_VALUE_TYPE value;
+ int top, topf, topg, index;
+
+ statLine(dd);
+ if (f == DD_PLUS_INFINITY(dd) || g == DD_PLUS_INFINITY(dd)) {
+ return(DD_PLUS_INFINITY(dd));
+ }
+
+ if (cuddIsConstant(f) && cuddIsConstant(g)) {
+ value = cuddV(f) + cuddV(g);
+ res = cuddUniqueConst(dd, value);
+ return(res);
+ }
+ if (f < g) {
+ DdNode *tmp = f;
+ f = g;
+ g = tmp;
+ }
+
+ if (f->ref != 1 || g->ref != 1) {
+ res = cuddCacheLookup(dd, DD_ADD_TRIANGLE_TAG, f, g, cube);
+ if (res != NULL) {
+ return(res);
+ }
+ }
+
+ topf = cuddI(dd,f->index); topg = cuddI(dd,g->index);
+ top = ddMin(topf,topg);
+
+ if (top == topf) {fv = cuddT(f); fvn = cuddE(f);} else {fv = fvn = f;}
+ if (top == topg) {gv = cuddT(g); gvn = cuddE(g);} else {gv = gvn = g;}
+
+ t = addTriangleRecur(dd, fv, gv, vars, cube);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ e = addTriangleRecur(dd, fvn, gvn, vars, cube);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ index = dd->invperm[top];
+ if (vars[index] < 0) {
+ res = (t == e) ? t : cuddUniqueInter(dd,index,t,e);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ Cudd_RecursiveDeref(dd, e);
+ return(NULL);
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+ } else {
+ res = cuddAddApplyRecur(dd,Cudd_addMinimum,t,e);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ Cudd_RecursiveDeref(dd, e);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd, t);
+ Cudd_RecursiveDeref(dd, e);
+ cuddDeref(res);
+ }
+
+ if (f->ref != 1 || g->ref != 1) {
+ cuddCacheInsert(dd, DD_ADD_TRIANGLE_TAG, f, g, cube, res);
+ }
+
+ return(res);
+
+} /* end of addTriangleRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addOuterSum.]
+
+ Description [Performs the recursive step of Cudd_addOuterSum.
+ Returns a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+cuddAddOuterSumRecur(
+ DdManager *dd,
+ DdNode *M,
+ DdNode *r,
+ DdNode *c)
+{
+ DdNode *P, *R, *Mt, *Me, *rt, *re, *ct, *ce, *Rt, *Re;
+ int topM, topc, topr;
+ int v, index;
+
+ statLine(dd);
+ /* Check special cases. */
+ if (r == DD_PLUS_INFINITY(dd) || c == DD_PLUS_INFINITY(dd)) return(M);
+
+ if (cuddIsConstant(c) && cuddIsConstant(r)) {
+ R = cuddUniqueConst(dd,Cudd_V(c)+Cudd_V(r));
+ cuddRef(R);
+ if (cuddIsConstant(M)) {
+ if (cuddV(R) <= cuddV(M)) {
+ cuddDeref(R);
+ return(R);
+ } else {
+ Cudd_RecursiveDeref(dd,R);
+ return(M);
+ }
+ } else {
+ P = Cudd_addApply(dd,Cudd_addMinimum,R,M);
+ cuddRef(P);
+ Cudd_RecursiveDeref(dd,R);
+ cuddDeref(P);
+ return(P);
+ }
+ }
+
+ /* Check the cache. */
+ R = cuddCacheLookup(dd,DD_ADD_OUT_SUM_TAG,M,r,c);
+ if (R != NULL) return(R);
+
+ topM = cuddI(dd,M->index); topr = cuddI(dd,r->index);
+ topc = cuddI(dd,c->index);
+ v = ddMin(topM,ddMin(topr,topc));
+
+ /* Compute cofactors. */
+ if (topM == v) { Mt = cuddT(M); Me = cuddE(M); } else { Mt = Me = M; }
+ if (topr == v) { rt = cuddT(r); re = cuddE(r); } else { rt = re = r; }
+ if (topc == v) { ct = cuddT(c); ce = cuddE(c); } else { ct = ce = c; }
+
+ /* Recursively solve. */
+ Rt = cuddAddOuterSumRecur(dd,Mt,rt,ct);
+ if (Rt == NULL) return(NULL);
+ cuddRef(Rt);
+ Re = cuddAddOuterSumRecur(dd,Me,re,ce);
+ if (Re == NULL) {
+ Cudd_RecursiveDeref(dd, Rt);
+ return(NULL);
+ }
+ cuddRef(Re);
+ index = dd->invperm[v];
+ R = (Rt == Re) ? Rt : cuddUniqueInter(dd,index,Rt,Re);
+ if (R == NULL) {
+ Cudd_RecursiveDeref(dd, Rt);
+ Cudd_RecursiveDeref(dd, Re);
+ return(NULL);
+ }
+ cuddDeref(Rt);
+ cuddDeref(Re);
+
+ /* Store the result in the cache. */
+ cuddCacheInsert(dd,DD_ADD_OUT_SUM_TAG,M,r,c,R);
+
+ return(R);
+
+} /* end of cuddAddOuterSumRecur */
diff --git a/src/bdd/cudd/cuddPriority.c b/src/bdd/cudd/cuddPriority.c
new file mode 100644
index 00000000..bb0b83d3
--- /dev/null
+++ b/src/bdd/cudd/cuddPriority.c
@@ -0,0 +1,1475 @@
+/**CFile***********************************************************************
+
+ FileName [cuddPriority.c]
+
+ PackageName [cudd]
+
+ Synopsis [Priority functions.]
+
+ Description [External procedures included in this file:
+ <ul>
+ <li> Cudd_PrioritySelect()
+ <li> Cudd_Xgty()
+ <li> Cudd_Xeqy()
+ <li> Cudd_addXeqy()
+ <li> Cudd_Dxygtdxz()
+ <li> Cudd_Dxygtdyz()
+ <li> Cudd_CProjection()
+ <li> Cudd_addHamming()
+ <li> Cudd_MinHammingDist()
+ <li> Cudd_bddClosestCube()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddCProjectionRecur()
+ <li> cuddBddClosestCube()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> cuddMinHammingDistRecur()
+ <li> separateCube()
+ <li> createResult()
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddPriority.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+static int cuddMinHammingDistRecur ARGS((DdNode * f, int *minterm, DdHashTable * table, int upperBound));
+static DdNode * separateCube ARGS((DdManager *dd, DdNode *f, CUDD_VALUE_TYPE *distance));
+static DdNode * createResult ARGS((DdManager *dd, unsigned int index, unsigned int phase, DdNode *cube, CUDD_VALUE_TYPE distance));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Selects pairs from R using a priority function.]
+
+ Description [Selects pairs from a relation R(x,y) (given as a BDD)
+ in such a way that a given x appears in one pair only. Uses a
+ priority function to determine which y should be paired to a given x.
+ Cudd_PrioritySelect returns a pointer to
+ the selected function if successful; NULL otherwise.
+ Three of the arguments--x, y, and z--are vectors of BDD variables.
+ The first two are the variables on which R depends. The third vectore
+ is a vector of auxiliary variables, used during the computation. This
+ vector is optional. If a NULL value is passed instead,
+ Cudd_PrioritySelect will create the working variables on the fly.
+ The sizes of x and y (and z if it is not NULL) should equal n.
+ The priority function Pi can be passed as a BDD, or can be built by
+ Cudd_PrioritySelect. If NULL is passed instead of a DdNode *,
+ parameter Pifunc is used by Cudd_PrioritySelect to build a BDD for the
+ priority function. (Pifunc is a pointer to a C function.) If Pi is not
+ NULL, then Pifunc is ignored. Pifunc should have the same interface as
+ the standard priority functions (e.g., Cudd_Dxygtdxz).
+ Cudd_PrioritySelect and Cudd_CProjection can sometimes be used
+ interchangeably. Specifically, calling Cudd_PrioritySelect with
+ Cudd_Xgty as Pifunc produces the same result as calling
+ Cudd_CProjection with the all-zero minterm as reference minterm.
+ However, depending on the application, one or the other may be
+ preferable:
+ <ul>
+ <li> When extracting representatives from an equivalence relation,
+ Cudd_CProjection has the advantage of nor requiring the auxiliary
+ variables.
+ <li> When computing matchings in general bipartite graphs,
+ Cudd_PrioritySelect normally obtains better results because it can use
+ more powerful matching schemes (e.g., Cudd_Dxygtdxz).
+ </ul>
+ ]
+
+ SideEffects [If called with z == NULL, will create new variables in
+ the manager.]
+
+ SeeAlso [Cudd_Dxygtdxz Cudd_Dxygtdyz Cudd_Xgty
+ Cudd_bddAdjPermuteX Cudd_CProjection]
+
+******************************************************************************/
+DdNode *
+Cudd_PrioritySelect(
+ DdManager * dd /* manager */,
+ DdNode * R /* BDD of the relation */,
+ DdNode ** x /* array of x variables */,
+ DdNode ** y /* array of y variables */,
+ DdNode ** z /* array of z variables (optional: may be NULL) */,
+ DdNode * Pi /* BDD of the priority function (optional: may be NULL) */,
+ int n /* size of x, y, and z */,
+ DdNode * (*Pifunc)(DdManager *, int, DdNode **, DdNode **, DdNode **) /* function used to build Pi if it is NULL */)
+{
+ DdNode *res = NULL;
+ DdNode *zcube = NULL;
+ DdNode *Rxz, *Q;
+ int createdZ = 0;
+ int createdPi = 0;
+ int i;
+
+ /* Create z variables if needed. */
+ if (z == NULL) {
+ if (Pi != NULL) return(NULL);
+ z = ALLOC(DdNode *,n);
+ if (z == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ createdZ = 1;
+ for (i = 0; i < n; i++) {
+ if (dd->size >= (int) CUDD_MAXINDEX - 1) goto endgame;
+ z[i] = cuddUniqueInter(dd,dd->size,dd->one,Cudd_Not(dd->one));
+ if (z[i] == NULL) goto endgame;
+ }
+ }
+
+ /* Create priority function BDD if needed. */
+ if (Pi == NULL) {
+ Pi = Pifunc(dd,n,x,y,z);
+ if (Pi == NULL) goto endgame;
+ createdPi = 1;
+ cuddRef(Pi);
+ }
+
+ /* Initialize abstraction cube. */
+ zcube = DD_ONE(dd);
+ cuddRef(zcube);
+ for (i = n - 1; i >= 0; i--) {
+ DdNode *tmpp;
+ tmpp = Cudd_bddAnd(dd,z[i],zcube);
+ if (tmpp == NULL) goto endgame;
+ cuddRef(tmpp);
+ Cudd_RecursiveDeref(dd,zcube);
+ zcube = tmpp;
+ }
+
+ /* Compute subset of (x,y) pairs. */
+ Rxz = Cudd_bddSwapVariables(dd,R,y,z,n);
+ if (Rxz == NULL) goto endgame;
+ cuddRef(Rxz);
+ Q = Cudd_bddAndAbstract(dd,Rxz,Pi,zcube);
+ if (Q == NULL) {
+ Cudd_RecursiveDeref(dd,Rxz);
+ goto endgame;
+ }
+ cuddRef(Q);
+ Cudd_RecursiveDeref(dd,Rxz);
+ res = Cudd_bddAnd(dd,R,Cudd_Not(Q));
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd,Q);
+ goto endgame;
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd,Q);
+
+endgame:
+ if (zcube != NULL) Cudd_RecursiveDeref(dd,zcube);
+ if (createdZ) {
+ FREE(z);
+ }
+ if (createdPi) {
+ Cudd_RecursiveDeref(dd,Pi);
+ }
+ if (res != NULL) cuddDeref(res);
+ return(res);
+
+} /* Cudd_PrioritySelect */
+
+
+/**Function********************************************************************
+
+ Synopsis [Generates a BDD for the function x &gt; y.]
+
+ Description [This function generates a BDD for the function x &gt; y.
+ Both x and y are N-bit numbers, x\[0\] x\[1\] ... x\[N-1\] and
+ y\[0\] y\[1\] ... y\[N-1\], with 0 the most significant bit.
+ The BDD is built bottom-up.
+ It has 3*N-1 internal nodes, if the variables are ordered as follows:
+ x\[0\] y\[0\] x\[1\] y\[1\] ... x\[N-1\] y\[N-1\].
+ Argument z is not used by Cudd_Xgty: it is included to make it
+ call-compatible to Cudd_Dxygtdxz and Cudd_Dxygtdyz.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_PrioritySelect Cudd_Dxygtdxz Cudd_Dxygtdyz]
+
+******************************************************************************/
+DdNode *
+Cudd_Xgty(
+ DdManager * dd /* DD manager */,
+ int N /* number of x and y variables */,
+ DdNode ** z /* array of z variables: unused */,
+ DdNode ** x /* array of x variables */,
+ DdNode ** y /* array of y variables */)
+{
+ DdNode *u, *v, *w;
+ int i;
+
+ /* Build bottom part of BDD outside loop. */
+ u = Cudd_bddAnd(dd, x[N-1], Cudd_Not(y[N-1]));
+ if (u == NULL) return(NULL);
+ cuddRef(u);
+
+ /* Loop to build the rest of the BDD. */
+ for (i = N-2; i >= 0; i--) {
+ v = Cudd_bddAnd(dd, y[i], Cudd_Not(u));
+ if (v == NULL) {
+ Cudd_RecursiveDeref(dd, u);
+ return(NULL);
+ }
+ cuddRef(v);
+ w = Cudd_bddAnd(dd, Cudd_Not(y[i]), u);
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, u);
+ Cudd_RecursiveDeref(dd, v);
+ return(NULL);
+ }
+ cuddRef(w);
+ Cudd_RecursiveDeref(dd, u);
+ u = Cudd_bddIte(dd, x[i], Cudd_Not(v), w);
+ if (u == NULL) {
+ Cudd_RecursiveDeref(dd, v);
+ Cudd_RecursiveDeref(dd, w);
+ return(NULL);
+ }
+ cuddRef(u);
+ Cudd_RecursiveDeref(dd, v);
+ Cudd_RecursiveDeref(dd, w);
+
+ }
+ cuddDeref(u);
+ return(u);
+
+} /* end of Cudd_Xgty */
+
+
+/**Function********************************************************************
+
+ Synopsis [Generates a BDD for the function x==y.]
+
+ Description [This function generates a BDD for the function x==y.
+ Both x and y are N-bit numbers, x\[0\] x\[1\] ... x\[N-1\] and
+ y\[0\] y\[1\] ... y\[N-1\], with 0 the most significant bit.
+ The BDD is built bottom-up.
+ It has 3*N-1 internal nodes, if the variables are ordered as follows:
+ x\[0\] y\[0\] x\[1\] y\[1\] ... x\[N-1\] y\[N-1\]. ]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addXeqy]
+
+******************************************************************************/
+DdNode *
+Cudd_Xeqy(
+ DdManager * dd /* DD manager */,
+ int N /* number of x and y variables */,
+ DdNode ** x /* array of x variables */,
+ DdNode ** y /* array of y variables */)
+{
+ DdNode *u, *v, *w;
+ int i;
+
+ /* Build bottom part of BDD outside loop. */
+ u = Cudd_bddIte(dd, x[N-1], y[N-1], Cudd_Not(y[N-1]));
+ if (u == NULL) return(NULL);
+ cuddRef(u);
+
+ /* Loop to build the rest of the BDD. */
+ for (i = N-2; i >= 0; i--) {
+ v = Cudd_bddAnd(dd, y[i], u);
+ if (v == NULL) {
+ Cudd_RecursiveDeref(dd, u);
+ return(NULL);
+ }
+ cuddRef(v);
+ w = Cudd_bddAnd(dd, Cudd_Not(y[i]), u);
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, u);
+ Cudd_RecursiveDeref(dd, v);
+ return(NULL);
+ }
+ cuddRef(w);
+ Cudd_RecursiveDeref(dd, u);
+ u = Cudd_bddIte(dd, x[i], v, w);
+ if (u == NULL) {
+ Cudd_RecursiveDeref(dd, v);
+ Cudd_RecursiveDeref(dd, w);
+ return(NULL);
+ }
+ cuddRef(u);
+ Cudd_RecursiveDeref(dd, v);
+ Cudd_RecursiveDeref(dd, w);
+ }
+ cuddDeref(u);
+ return(u);
+
+} /* end of Cudd_Xeqy */
+
+
+/**Function********************************************************************
+
+ Synopsis [Generates an ADD for the function x==y.]
+
+ Description [This function generates an ADD for the function x==y.
+ Both x and y are N-bit numbers, x\[0\] x\[1\] ... x\[N-1\] and
+ y\[0\] y\[1\] ... y\[N-1\], with 0 the most significant bit.
+ The ADD is built bottom-up.
+ It has 3*N-1 internal nodes, if the variables are ordered as follows:
+ x\[0\] y\[0\] x\[1\] y\[1\] ... x\[N-1\] y\[N-1\]. ]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Xeqy]
+
+******************************************************************************/
+DdNode *
+Cudd_addXeqy(
+ DdManager * dd /* DD manager */,
+ int N /* number of x and y variables */,
+ DdNode ** x /* array of x variables */,
+ DdNode ** y /* array of y variables */)
+{
+ DdNode *one, *zero;
+ DdNode *u, *v, *w;
+ int i;
+
+ one = DD_ONE(dd);
+ zero = DD_ZERO(dd);
+
+ /* Build bottom part of ADD outside loop. */
+ v = Cudd_addIte(dd, y[N-1], one, zero);
+ if (v == NULL) return(NULL);
+ cuddRef(v);
+ w = Cudd_addIte(dd, y[N-1], zero, one);
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, v);
+ return(NULL);
+ }
+ cuddRef(w);
+ u = Cudd_addIte(dd, x[N-1], v, w);
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, v);
+ Cudd_RecursiveDeref(dd, w);
+ return(NULL);
+ }
+ cuddRef(u);
+ Cudd_RecursiveDeref(dd, v);
+ Cudd_RecursiveDeref(dd, w);
+
+ /* Loop to build the rest of the ADD. */
+ for (i = N-2; i >= 0; i--) {
+ v = Cudd_addIte(dd, y[i], u, zero);
+ if (v == NULL) {
+ Cudd_RecursiveDeref(dd, u);
+ return(NULL);
+ }
+ cuddRef(v);
+ w = Cudd_addIte(dd, y[i], zero, u);
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, u);
+ Cudd_RecursiveDeref(dd, v);
+ return(NULL);
+ }
+ cuddRef(w);
+ Cudd_RecursiveDeref(dd, u);
+ u = Cudd_addIte(dd, x[i], v, w);
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, v);
+ Cudd_RecursiveDeref(dd, w);
+ return(NULL);
+ }
+ cuddRef(u);
+ Cudd_RecursiveDeref(dd, v);
+ Cudd_RecursiveDeref(dd, w);
+ }
+ cuddDeref(u);
+ return(u);
+
+} /* end of Cudd_addXeqy */
+
+
+/**Function********************************************************************
+
+ Synopsis [Generates a BDD for the function d(x,y) &gt; d(x,z).]
+
+ Description [This function generates a BDD for the function d(x,y)
+ &gt; d(x,z);
+ x, y, and z are N-bit numbers, x\[0\] x\[1\] ... x\[N-1\],
+ y\[0\] y\[1\] ... y\[N-1\], and z\[0\] z\[1\] ... z\[N-1\],
+ with 0 the most significant bit.
+ The distance d(x,y) is defined as:
+ \sum_{i=0}^{N-1}(|x_i - y_i| \cdot 2^{N-i-1}).
+ The BDD is built bottom-up.
+ It has 7*N-3 internal nodes, if the variables are ordered as follows:
+ x\[0\] y\[0\] z\[0\] x\[1\] y\[1\] z\[1\] ... x\[N-1\] y\[N-1\] z\[N-1\]. ]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_PrioritySelect Cudd_Dxygtdyz Cudd_Xgty Cudd_bddAdjPermuteX]
+
+******************************************************************************/
+DdNode *
+Cudd_Dxygtdxz(
+ DdManager * dd /* DD manager */,
+ int N /* number of x, y, and z variables */,
+ DdNode ** x /* array of x variables */,
+ DdNode ** y /* array of y variables */,
+ DdNode ** z /* array of z variables */)
+{
+ DdNode *one, *zero;
+ DdNode *z1, *z2, *z3, *z4, *y1_, *y2, *x1;
+ int i;
+
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+
+ /* Build bottom part of BDD outside loop. */
+ y1_ = Cudd_bddIte(dd, y[N-1], one, Cudd_Not(z[N-1]));
+ if (y1_ == NULL) return(NULL);
+ cuddRef(y1_);
+ y2 = Cudd_bddIte(dd, y[N-1], z[N-1], one);
+ if (y2 == NULL) {
+ Cudd_RecursiveDeref(dd, y1_);
+ return(NULL);
+ }
+ cuddRef(y2);
+ x1 = Cudd_bddIte(dd, x[N-1], y1_, y2);
+ if (x1 == NULL) {
+ Cudd_RecursiveDeref(dd, y1_);
+ Cudd_RecursiveDeref(dd, y2);
+ return(NULL);
+ }
+ cuddRef(x1);
+ Cudd_RecursiveDeref(dd, y1_);
+ Cudd_RecursiveDeref(dd, y2);
+
+ /* Loop to build the rest of the BDD. */
+ for (i = N-2; i >= 0; i--) {
+ z1 = Cudd_bddIte(dd, z[i], one, Cudd_Not(x1));
+ if (z1 == NULL) {
+ Cudd_RecursiveDeref(dd, x1);
+ return(NULL);
+ }
+ cuddRef(z1);
+ z2 = Cudd_bddIte(dd, z[i], x1, one);
+ if (z2 == NULL) {
+ Cudd_RecursiveDeref(dd, x1);
+ Cudd_RecursiveDeref(dd, z1);
+ return(NULL);
+ }
+ cuddRef(z2);
+ z3 = Cudd_bddIte(dd, z[i], one, x1);
+ if (z3 == NULL) {
+ Cudd_RecursiveDeref(dd, x1);
+ Cudd_RecursiveDeref(dd, z1);
+ Cudd_RecursiveDeref(dd, z2);
+ return(NULL);
+ }
+ cuddRef(z3);
+ z4 = Cudd_bddIte(dd, z[i], x1, zero);
+ if (z4 == NULL) {
+ Cudd_RecursiveDeref(dd, x1);
+ Cudd_RecursiveDeref(dd, z1);
+ Cudd_RecursiveDeref(dd, z2);
+ Cudd_RecursiveDeref(dd, z3);
+ return(NULL);
+ }
+ cuddRef(z4);
+ Cudd_RecursiveDeref(dd, x1);
+ y1_ = Cudd_bddIte(dd, y[i], z2, Cudd_Not(z1));
+ if (y1_ == NULL) {
+ Cudd_RecursiveDeref(dd, z1);
+ Cudd_RecursiveDeref(dd, z2);
+ Cudd_RecursiveDeref(dd, z3);
+ Cudd_RecursiveDeref(dd, z4);
+ return(NULL);
+ }
+ cuddRef(y1_);
+ y2 = Cudd_bddIte(dd, y[i], z4, z3);
+ if (y2 == NULL) {
+ Cudd_RecursiveDeref(dd, z1);
+ Cudd_RecursiveDeref(dd, z2);
+ Cudd_RecursiveDeref(dd, z3);
+ Cudd_RecursiveDeref(dd, z4);
+ Cudd_RecursiveDeref(dd, y1_);
+ return(NULL);
+ }
+ cuddRef(y2);
+ Cudd_RecursiveDeref(dd, z1);
+ Cudd_RecursiveDeref(dd, z2);
+ Cudd_RecursiveDeref(dd, z3);
+ Cudd_RecursiveDeref(dd, z4);
+ x1 = Cudd_bddIte(dd, x[i], y1_, y2);
+ if (x1 == NULL) {
+ Cudd_RecursiveDeref(dd, y1_);
+ Cudd_RecursiveDeref(dd, y2);
+ return(NULL);
+ }
+ cuddRef(x1);
+ Cudd_RecursiveDeref(dd, y1_);
+ Cudd_RecursiveDeref(dd, y2);
+ }
+ cuddDeref(x1);
+ return(Cudd_Not(x1));
+
+} /* end of Cudd_Dxygtdxz */
+
+
+/**Function********************************************************************
+
+ Synopsis [Generates a BDD for the function d(x,y) &gt; d(y,z).]
+
+ Description [This function generates a BDD for the function d(x,y)
+ &gt; d(y,z);
+ x, y, and z are N-bit numbers, x\[0\] x\[1\] ... x\[N-1\],
+ y\[0\] y\[1\] ... y\[N-1\], and z\[0\] z\[1\] ... z\[N-1\],
+ with 0 the most significant bit.
+ The distance d(x,y) is defined as:
+ \sum_{i=0}^{N-1}(|x_i - y_i| \cdot 2^{N-i-1}).
+ The BDD is built bottom-up.
+ It has 7*N-3 internal nodes, if the variables are ordered as follows:
+ x\[0\] y\[0\] z\[0\] x\[1\] y\[1\] z\[1\] ... x\[N-1\] y\[N-1\] z\[N-1\]. ]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_PrioritySelect Cudd_Dxygtdxz Cudd_Xgty Cudd_bddAdjPermuteX]
+
+******************************************************************************/
+DdNode *
+Cudd_Dxygtdyz(
+ DdManager * dd /* DD manager */,
+ int N /* number of x, y, and z variables */,
+ DdNode ** x /* array of x variables */,
+ DdNode ** y /* array of y variables */,
+ DdNode ** z /* array of z variables */)
+{
+ DdNode *one, *zero;
+ DdNode *z1, *z2, *z3, *z4, *y1_, *y2, *x1;
+ int i;
+
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+
+ /* Build bottom part of BDD outside loop. */
+ y1_ = Cudd_bddIte(dd, y[N-1], one, z[N-1]);
+ if (y1_ == NULL) return(NULL);
+ cuddRef(y1_);
+ y2 = Cudd_bddIte(dd, y[N-1], z[N-1], zero);
+ if (y2 == NULL) {
+ Cudd_RecursiveDeref(dd, y1_);
+ return(NULL);
+ }
+ cuddRef(y2);
+ x1 = Cudd_bddIte(dd, x[N-1], y1_, Cudd_Not(y2));
+ if (x1 == NULL) {
+ Cudd_RecursiveDeref(dd, y1_);
+ Cudd_RecursiveDeref(dd, y2);
+ return(NULL);
+ }
+ cuddRef(x1);
+ Cudd_RecursiveDeref(dd, y1_);
+ Cudd_RecursiveDeref(dd, y2);
+
+ /* Loop to build the rest of the BDD. */
+ for (i = N-2; i >= 0; i--) {
+ z1 = Cudd_bddIte(dd, z[i], x1, zero);
+ if (z1 == NULL) {
+ Cudd_RecursiveDeref(dd, x1);
+ return(NULL);
+ }
+ cuddRef(z1);
+ z2 = Cudd_bddIte(dd, z[i], x1, one);
+ if (z2 == NULL) {
+ Cudd_RecursiveDeref(dd, x1);
+ Cudd_RecursiveDeref(dd, z1);
+ return(NULL);
+ }
+ cuddRef(z2);
+ z3 = Cudd_bddIte(dd, z[i], one, x1);
+ if (z3 == NULL) {
+ Cudd_RecursiveDeref(dd, x1);
+ Cudd_RecursiveDeref(dd, z1);
+ Cudd_RecursiveDeref(dd, z2);
+ return(NULL);
+ }
+ cuddRef(z3);
+ z4 = Cudd_bddIte(dd, z[i], one, Cudd_Not(x1));
+ if (z4 == NULL) {
+ Cudd_RecursiveDeref(dd, x1);
+ Cudd_RecursiveDeref(dd, z1);
+ Cudd_RecursiveDeref(dd, z2);
+ Cudd_RecursiveDeref(dd, z3);
+ return(NULL);
+ }
+ cuddRef(z4);
+ Cudd_RecursiveDeref(dd, x1);
+ y1_ = Cudd_bddIte(dd, y[i], z2, z1);
+ if (y1_ == NULL) {
+ Cudd_RecursiveDeref(dd, z1);
+ Cudd_RecursiveDeref(dd, z2);
+ Cudd_RecursiveDeref(dd, z3);
+ Cudd_RecursiveDeref(dd, z4);
+ return(NULL);
+ }
+ cuddRef(y1_);
+ y2 = Cudd_bddIte(dd, y[i], z4, Cudd_Not(z3));
+ if (y2 == NULL) {
+ Cudd_RecursiveDeref(dd, z1);
+ Cudd_RecursiveDeref(dd, z2);
+ Cudd_RecursiveDeref(dd, z3);
+ Cudd_RecursiveDeref(dd, z4);
+ Cudd_RecursiveDeref(dd, y1_);
+ return(NULL);
+ }
+ cuddRef(y2);
+ Cudd_RecursiveDeref(dd, z1);
+ Cudd_RecursiveDeref(dd, z2);
+ Cudd_RecursiveDeref(dd, z3);
+ Cudd_RecursiveDeref(dd, z4);
+ x1 = Cudd_bddIte(dd, x[i], y1_, Cudd_Not(y2));
+ if (x1 == NULL) {
+ Cudd_RecursiveDeref(dd, y1_);
+ Cudd_RecursiveDeref(dd, y2);
+ return(NULL);
+ }
+ cuddRef(x1);
+ Cudd_RecursiveDeref(dd, y1_);
+ Cudd_RecursiveDeref(dd, y2);
+ }
+ cuddDeref(x1);
+ return(Cudd_Not(x1));
+
+} /* end of Cudd_Dxygtdyz */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the compatible projection of R w.r.t. cube Y.]
+
+ Description [Computes the compatible projection of relation R with
+ respect to cube Y. Returns a pointer to the c-projection if
+ successful; NULL otherwise. For a comparison between Cudd_CProjection
+ and Cudd_PrioritySelect, see the documentation of the latter.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_PrioritySelect]
+
+******************************************************************************/
+DdNode *
+Cudd_CProjection(
+ DdManager * dd,
+ DdNode * R,
+ DdNode * Y)
+{
+ DdNode *res;
+ DdNode *support;
+
+ if (cuddCheckCube(dd,Y) == 0) {
+ (void) fprintf(dd->err,
+ "Error: The third argument of Cudd_CProjection should be a cube\n");
+ dd->errorCode = CUDD_INVALID_ARG;
+ return(NULL);
+ }
+
+ /* Compute the support of Y, which is used by the abstraction step
+ ** in cuddCProjectionRecur.
+ */
+ support = Cudd_Support(dd,Y);
+ if (support == NULL) return(NULL);
+ cuddRef(support);
+
+ do {
+ dd->reordered = 0;
+ res = cuddCProjectionRecur(dd,R,Y,support);
+ } while (dd->reordered == 1);
+
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd,support);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd,support);
+ cuddDeref(res);
+
+ return(res);
+
+} /* end of Cudd_CProjection */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the Hamming distance ADD.]
+
+ Description [Computes the Hamming distance ADD. Returns an ADD that
+ gives the Hamming distance between its two arguments if successful;
+ NULL otherwise. The two vectors xVars and yVars identify the variables
+ that form the two arguments.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_addHamming(
+ DdManager * dd,
+ DdNode ** xVars,
+ DdNode ** yVars,
+ int nVars)
+{
+ DdNode *result,*tempBdd;
+ DdNode *tempAdd,*temp;
+ int i;
+
+ result = DD_ZERO(dd);
+ cuddRef(result);
+
+ for (i = 0; i < nVars; i++) {
+ tempBdd = Cudd_bddIte(dd,xVars[i],Cudd_Not(yVars[i]),yVars[i]);
+ if (tempBdd == NULL) {
+ Cudd_RecursiveDeref(dd,result);
+ return(NULL);
+ }
+ cuddRef(tempBdd);
+ tempAdd = Cudd_BddToAdd(dd,tempBdd);
+ if (tempAdd == NULL) {
+ Cudd_RecursiveDeref(dd,tempBdd);
+ Cudd_RecursiveDeref(dd,result);
+ return(NULL);
+ }
+ cuddRef(tempAdd);
+ Cudd_RecursiveDeref(dd,tempBdd);
+ temp = Cudd_addApply(dd,Cudd_addPlus,tempAdd,result);
+ if (temp == NULL) {
+ Cudd_RecursiveDeref(dd,tempAdd);
+ Cudd_RecursiveDeref(dd,result);
+ return(NULL);
+ }
+ cuddRef(temp);
+ Cudd_RecursiveDeref(dd,tempAdd);
+ Cudd_RecursiveDeref(dd,result);
+ result = temp;
+ }
+
+ cuddDeref(result);
+ return(result);
+
+} /* end of Cudd_addHamming */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the minimum Hamming distance between f and minterm.]
+
+ Description [Returns the minimum Hamming distance between the
+ minterms of a function f and a reference minterm. The function is
+ given as a BDD; the minterm is given as an array of integers, one
+ for each variable in the manager. Returns the minimum distance if
+ it is less than the upper bound; the upper bound if the minimum
+ distance is at least as large; CUDD_OUT_OF_MEM in case of failure.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addHamming Cudd_bddClosestCube]
+
+******************************************************************************/
+int
+Cudd_MinHammingDist(
+ DdManager *dd /* DD manager */,
+ DdNode *f /* function to examine */,
+ int *minterm /* reference minterm */,
+ int upperBound /* distance above which an approximate answer is OK */)
+{
+ DdHashTable *table;
+ CUDD_VALUE_TYPE epsilon;
+ int res;
+
+ table = cuddHashTableInit(dd,1,2);
+ if (table == NULL) {
+ return(CUDD_OUT_OF_MEM);
+ }
+ epsilon = Cudd_ReadEpsilon(dd);
+ Cudd_SetEpsilon(dd,(CUDD_VALUE_TYPE)0.0);
+ res = cuddMinHammingDistRecur(f,minterm,table,upperBound);
+ cuddHashTableQuit(table);
+ Cudd_SetEpsilon(dd,epsilon);
+
+ return(res);
+
+} /* end of Cudd_MinHammingDist */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds a cube of f at minimum Hamming distance from g.]
+
+ Description [Finds a cube of f at minimum Hamming distance from the
+ minterms of g. All the minterms of the cube are at the minimum
+ distance. If the distance is 0, the cube belongs to the
+ intersection of f and g. Returns the cube if successful; NULL
+ otherwise.]
+
+ SideEffects [The distance is returned as a side effect.]
+
+ SeeAlso [Cudd_MinHammingDist]
+
+******************************************************************************/
+DdNode *
+Cudd_bddClosestCube(
+ DdManager *dd,
+ DdNode * f,
+ DdNode *g,
+ int *distance)
+{
+ DdNode *res, *acube;
+ CUDD_VALUE_TYPE rdist;
+
+ /* Compute the cube and distance as a single ADD. */
+ do {
+ dd->reordered = 0;
+ res = cuddBddClosestCube(dd,f,g,CUDD_CONST_INDEX + 1.0);
+ } while (dd->reordered == 1);
+ if (res == NULL) return(NULL);
+ cuddRef(res);
+
+ /* Unpack distance and cube. */
+ do {
+ dd->reordered = 0;
+ acube = separateCube(dd, res, &rdist);
+ } while (dd->reordered == 1);
+ if (acube == NULL) {
+ Cudd_RecursiveDeref(dd, res);
+ return(NULL);
+ }
+ cuddRef(acube);
+ Cudd_RecursiveDeref(dd, res);
+
+ /* Convert cube from ADD to BDD. */
+ do {
+ dd->reordered = 0;
+ res = cuddAddBddDoPattern(dd, acube);
+ } while (dd->reordered == 1);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, acube);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd, acube);
+
+ *distance = (int) rdist;
+ cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_bddClosestCube */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_CProjection.]
+
+ Description [Performs the recursive step of Cudd_CProjection. Returns
+ the projection if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_CProjection]
+
+******************************************************************************/
+DdNode *
+cuddCProjectionRecur(
+ DdManager * dd,
+ DdNode * R,
+ DdNode * Y,
+ DdNode * Ysupp)
+{
+ DdNode *res, *res1, *res2, *resA;
+ DdNode *r, *y, *RT, *RE, *YT, *YE, *Yrest, *Ra, *Ran, *Gamma, *Alpha;
+ unsigned int topR, topY, top, index;
+ DdNode *one = DD_ONE(dd);
+
+ statLine(dd);
+ if (Y == one) return(R);
+
+#ifdef DD_DEBUG
+ assert(!Cudd_IsConstant(Y));
+#endif
+
+ if (R == Cudd_Not(one)) return(R);
+
+ res = cuddCacheLookup2(dd, Cudd_CProjection, R, Y);
+ if (res != NULL) return(res);
+
+ r = Cudd_Regular(R);
+ topR = cuddI(dd,r->index);
+ y = Cudd_Regular(Y);
+ topY = cuddI(dd,y->index);
+
+ top = ddMin(topR, topY);
+
+ /* Compute the cofactors of R */
+ if (topR == top) {
+ index = r->index;
+ RT = cuddT(r);
+ RE = cuddE(r);
+ if (r != R) {
+ RT = Cudd_Not(RT); RE = Cudd_Not(RE);
+ }
+ } else {
+ RT = RE = R;
+ }
+
+ if (topY > top) {
+ /* Y does not depend on the current top variable.
+ ** We just need to compute the results on the two cofactors of R
+ ** and make them the children of a node labeled r->index.
+ */
+ res1 = cuddCProjectionRecur(dd,RT,Y,Ysupp);
+ if (res1 == NULL) return(NULL);
+ cuddRef(res1);
+ res2 = cuddCProjectionRecur(dd,RE,Y,Ysupp);
+ if (res2 == NULL) {
+ Cudd_RecursiveDeref(dd,res1);
+ return(NULL);
+ }
+ cuddRef(res2);
+ res = cuddBddIteRecur(dd, dd->vars[index], res1, res2);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd,res1);
+ Cudd_RecursiveDeref(dd,res2);
+ return(NULL);
+ }
+ /* If we have reached this point, res1 and res2 are now
+ ** incorporated in res. cuddDeref is therefore sufficient.
+ */
+ cuddDeref(res1);
+ cuddDeref(res2);
+ } else {
+ /* Compute the cofactors of Y */
+ index = y->index;
+ YT = cuddT(y);
+ YE = cuddE(y);
+ if (y != Y) {
+ YT = Cudd_Not(YT); YE = Cudd_Not(YE);
+ }
+ if (YT == Cudd_Not(one)) {
+ Alpha = Cudd_Not(dd->vars[index]);
+ Yrest = YE;
+ Ra = RE;
+ Ran = RT;
+ } else {
+ Alpha = dd->vars[index];
+ Yrest = YT;
+ Ra = RT;
+ Ran = RE;
+ }
+ Gamma = cuddBddExistAbstractRecur(dd,Ra,cuddT(Ysupp));
+ if (Gamma == NULL) return(NULL);
+ if (Gamma == one) {
+ res1 = cuddCProjectionRecur(dd,Ra,Yrest,cuddT(Ysupp));
+ if (res1 == NULL) return(NULL);
+ cuddRef(res1);
+ res = cuddBddAndRecur(dd, Alpha, res1);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd,res1);
+ return(NULL);
+ }
+ cuddDeref(res1);
+ } else if (Gamma == Cudd_Not(one)) {
+ res1 = cuddCProjectionRecur(dd,Ran,Yrest,cuddT(Ysupp));
+ if (res1 == NULL) return(NULL);
+ cuddRef(res1);
+ res = cuddBddAndRecur(dd, Cudd_Not(Alpha), res1);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd,res1);
+ return(NULL);
+ }
+ cuddDeref(res1);
+ } else {
+ cuddRef(Gamma);
+ resA = cuddCProjectionRecur(dd,Ran,Yrest,cuddT(Ysupp));
+ if (resA == NULL) {
+ Cudd_RecursiveDeref(dd,Gamma);
+ return(NULL);
+ }
+ cuddRef(resA);
+ res2 = cuddBddAndRecur(dd, Cudd_Not(Gamma), resA);
+ if (res2 == NULL) {
+ Cudd_RecursiveDeref(dd,Gamma);
+ Cudd_RecursiveDeref(dd,resA);
+ return(NULL);
+ }
+ cuddRef(res2);
+ Cudd_RecursiveDeref(dd,Gamma);
+ Cudd_RecursiveDeref(dd,resA);
+ res1 = cuddCProjectionRecur(dd,Ra,Yrest,cuddT(Ysupp));
+ if (res1 == NULL) {
+ Cudd_RecursiveDeref(dd,res2);
+ return(NULL);
+ }
+ cuddRef(res1);
+ res = cuddBddIteRecur(dd, Alpha, res1, res2);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd,res1);
+ Cudd_RecursiveDeref(dd,res2);
+ return(NULL);
+ }
+ cuddDeref(res1);
+ cuddDeref(res2);
+ }
+ }
+
+ cuddCacheInsert2(dd,Cudd_CProjection,R,Y,res);
+
+ return(res);
+
+} /* end of cuddCProjectionRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddClosestCube.]
+
+ Description [Performs the recursive step of Cudd_bddClosestCube.
+ Returns the cube if succesful; NULL otherwise. The procedure uses a
+ four-way recursion to examine all four combinations of cofactors of
+ f and g. The most interesting feature of this function is the
+ scheme used for caching the results in the global computed table.
+ Since we have a cube and a distance, we combine them to form an ADD.
+ The combination replaces the zero child of the top node of the cube
+ with the negative of the distance. (The use of the negative is to
+ avoid ambiguity with 1.) The degenerate cases (zero and one) are
+ treated specially because the distance is known (0 for one, and
+ infinity for zero).]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddClosestCube]
+
+******************************************************************************/
+DdNode *
+cuddBddClosestCube(
+ DdManager *dd,
+ DdNode *f,
+ DdNode *g,
+ CUDD_VALUE_TYPE bound)
+{
+ DdNode *res, *F, *G, *ft, *fe, *gt, *ge, *tt, *ee;
+ DdNode *ctt, *cee, *cte, *cet;
+ CUDD_VALUE_TYPE minD, dtt, dee, dte, det;
+ DdNode *one = DD_ONE(dd);
+ DdNode *lzero = Cudd_Not(one);
+ DdNode *azero = DD_ZERO(dd);
+ unsigned int topf, topg, index;
+
+ statLine(dd);
+ if (bound < (f == Cudd_Not(g))) return(azero);
+ /* Terminal cases. */
+ if (g == lzero || f == lzero) return(azero);
+ if (f == one && g == one) return(one);
+
+ /* Check cache. */
+ F = Cudd_Regular(f);
+ G = Cudd_Regular(g);
+ if (F->ref != 1 || G->ref != 1) {
+ res = cuddCacheLookup2(dd,(DdNode * (*)(DdManager *, DdNode *,
+ DdNode *)) Cudd_bddClosestCube, f, g);
+ if (res != NULL) return(res);
+ }
+
+ topf = cuddI(dd,F->index);
+ topg = cuddI(dd,G->index);
+
+ /* Compute cofactors. */
+ if (topf <= topg) {
+ index = F->index;
+ ft = cuddT(F);
+ fe = cuddE(F);
+ if (Cudd_IsComplement(f)) {
+ ft = Cudd_Not(ft);
+ fe = Cudd_Not(fe);
+ }
+ } else {
+ index = G->index;
+ ft = fe = f;
+ }
+
+ if (topg <= topf) {
+ gt = cuddT(G);
+ ge = cuddE(G);
+ if (Cudd_IsComplement(g)) {
+ gt = Cudd_Not(gt);
+ ge = Cudd_Not(ge);
+ }
+ } else {
+ gt = ge = g;
+ }
+
+ tt = cuddBddClosestCube(dd,ft,gt,bound);
+ if (tt == NULL) return(NULL);
+ cuddRef(tt);
+ ctt = separateCube(dd,tt,&dtt);
+ if (ctt == NULL) {
+ Cudd_RecursiveDeref(dd, tt);
+ return(NULL);
+ }
+ cuddRef(ctt);
+ Cudd_RecursiveDeref(dd, tt);
+ minD = dtt;
+ bound = ddMin(bound,minD);
+
+ ee = cuddBddClosestCube(dd,fe,ge,bound);
+ if (ee == NULL) {
+ Cudd_RecursiveDeref(dd, ctt);
+ return(NULL);
+ }
+ cuddRef(ee);
+ cee = separateCube(dd,ee,&dee);
+ if (cee == NULL) {
+ Cudd_RecursiveDeref(dd, ctt);
+ Cudd_RecursiveDeref(dd, ee);
+ return(NULL);
+ }
+ cuddRef(cee);
+ Cudd_RecursiveDeref(dd, ee);
+ minD = ddMin(dtt, dee);
+ bound = ddMin(bound,minD-1);
+
+ if (minD > 0 && topf == topg) {
+ DdNode *te = cuddBddClosestCube(dd,ft,ge,bound-1);
+ if (te == NULL) {
+ Cudd_RecursiveDeref(dd, ctt);
+ Cudd_RecursiveDeref(dd, cee);
+ return(NULL);
+ }
+ cuddRef(te);
+ cte = separateCube(dd,te,&dte);
+ if (cte == NULL) {
+ Cudd_RecursiveDeref(dd, ctt);
+ Cudd_RecursiveDeref(dd, cee);
+ Cudd_RecursiveDeref(dd, te);
+ return(NULL);
+ }
+ cuddRef(cte);
+ Cudd_RecursiveDeref(dd, te);
+ dte += 1.0;
+ minD = ddMin(minD, dte);
+ } else {
+ cte = azero;
+ cuddRef(cte);
+ dte = CUDD_CONST_INDEX + 1.0;
+ }
+ bound = ddMin(bound,minD-1);
+
+ if (minD > 0 && topf == topg) {
+ DdNode *et = cuddBddClosestCube(dd,fe,gt,bound-1);
+ if (et == NULL) {
+ Cudd_RecursiveDeref(dd, ctt);
+ Cudd_RecursiveDeref(dd, cee);
+ Cudd_RecursiveDeref(dd, cte);
+ return(NULL);
+ }
+ cuddRef(et);
+ cet = separateCube(dd,et,&det);
+ if (cet == NULL) {
+ Cudd_RecursiveDeref(dd, ctt);
+ Cudd_RecursiveDeref(dd, cee);
+ Cudd_RecursiveDeref(dd, cte);
+ Cudd_RecursiveDeref(dd, et);
+ return(NULL);
+ }
+ cuddRef(cet);
+ Cudd_RecursiveDeref(dd, et);
+ det += 1.0;
+ minD = ddMin(minD, det);
+ } else {
+ cet = azero;
+ cuddRef(cet);
+ det = CUDD_CONST_INDEX + 1.0;
+ }
+
+ if (minD == dtt) {
+ if (dtt == dee && ctt == cee) {
+ res = createResult(dd,CUDD_CONST_INDEX,1,ctt,dtt);
+ } else {
+ res = createResult(dd,index,1,ctt,dtt);
+ }
+ } else if (minD == dee) {
+ res = createResult(dd,index,0,cee,dee);
+ } else if (minD == dte) {
+ res = createResult(dd,index,(topf <= topg),cte,dte);
+ } else {
+ res = createResult(dd,index,(topf > topg),cet,det);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd, ctt);
+ Cudd_RecursiveDeref(dd, cee);
+ Cudd_RecursiveDeref(dd, cte);
+ Cudd_RecursiveDeref(dd, cet);
+
+ if (F->ref != 1 || G->ref != 1)
+ cuddCacheInsert2(dd,(DdNode * (*)(DdManager *, DdNode *,
+ DdNode *)) Cudd_bddClosestCube, f, g, res);
+
+ cuddDeref(res);
+ return(res);
+
+} /* end of cuddBddClosestCube */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_MinHammingDist.]
+
+ Description [Performs the recursive step of Cudd_MinHammingDist.
+ It is based on the following identity. Let H(f) be the
+ minimum Hamming distance of the minterms of f from the reference
+ minterm. Then:
+ <xmp>
+ H(f) = min(H(f0)+h0,H(f1)+h1)
+ </xmp>
+ where f0 and f1 are the two cofactors of f with respect to its top
+ variable; h0 is 1 if the minterm assigns 1 to the top variable of f;
+ h1 is 1 if the minterm assigns 0 to the top variable of f.
+ The upper bound on the distance is used to bound the depth of the
+ recursion.
+ Returns the minimum distance unless it exceeds the upper bound or
+ computation fails.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_MinHammingDist]
+
+******************************************************************************/
+static int
+cuddMinHammingDistRecur(
+ DdNode * f,
+ int *minterm,
+ DdHashTable * table,
+ int upperBound)
+{
+ DdNode *F, *Ft, *Fe;
+ double h, hT, hE;
+ DdNode *zero, *res;
+ DdManager *dd = table->manager;
+
+ statLine(dd);
+ if (upperBound == 0) return(0);
+
+ F = Cudd_Regular(f);
+
+ if (cuddIsConstant(F)) {
+ zero = Cudd_Not(DD_ONE(dd));
+ if (f == dd->background || f == zero) {
+ return(upperBound);
+ } else {
+ return(0);
+ }
+ }
+ if ((res = cuddHashTableLookup1(table,f)) != NULL) {
+ h = cuddV(res);
+ if (res->ref == 0) {
+ dd->dead++;
+ dd->constants.dead++;
+ }
+ return((int) h);
+ }
+
+ Ft = cuddT(F); Fe = cuddE(F);
+ if (Cudd_IsComplement(f)) {
+ Ft = Cudd_Not(Ft); Fe = Cudd_Not(Fe);
+ }
+ if (minterm[F->index] == 0) {
+ DdNode *temp = Ft;
+ Ft = Fe; Fe = temp;
+ }
+
+ hT = cuddMinHammingDistRecur(Ft,minterm,table,upperBound);
+ if (hT == CUDD_OUT_OF_MEM) return(CUDD_OUT_OF_MEM);
+ if (hT == 0) {
+ hE = upperBound;
+ } else {
+ hE = cuddMinHammingDistRecur(Fe,minterm,table,upperBound - 1);
+ if (hE == CUDD_OUT_OF_MEM) return(CUDD_OUT_OF_MEM);
+ }
+ h = ddMin(hT, hE + 1);
+
+ if (F->ref != 1) {
+ ptrint fanout = (ptrint) F->ref;
+ cuddSatDec(fanout);
+ res = cuddUniqueConst(dd, (CUDD_VALUE_TYPE) h);
+ if (!cuddHashTableInsert1(table,f,res,fanout)) {
+ cuddRef(res); Cudd_RecursiveDeref(dd, res);
+ return(CUDD_OUT_OF_MEM);
+ }
+ }
+
+ return((int) h);
+
+} /* end of cuddMinHammingDistRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Separates cube from distance.]
+
+ Description [Separates cube from distance. Returns the cube if
+ successful; NULL otherwise.]
+
+ SideEffects [The distance is returned as a side effect.]
+
+ SeeAlso [cuddBddClosestCube createResult]
+
+******************************************************************************/
+static DdNode *
+separateCube(
+ DdManager *dd,
+ DdNode *f,
+ CUDD_VALUE_TYPE *distance)
+{
+ DdNode *cube, *t;
+
+ /* One and zero are special cases because the distance is implied. */
+ if (Cudd_IsConstant(f)) {
+ *distance = (f == DD_ONE(dd)) ? 0.0 :
+ (1.0 + (CUDD_VALUE_TYPE) CUDD_CONST_INDEX);
+ return(f);
+ }
+
+ /* Find out which branch points to the distance and replace the top
+ ** node with one pointing to zero instead. */
+ t = cuddT(f);
+ if (Cudd_IsConstant(t) && cuddV(t) <= 0) {
+#ifdef DD_DEBUG
+ assert(!Cudd_IsConstant(cuddE(f)) || cuddE(f) == DD_ONE(dd));
+#endif
+ *distance = -cuddV(t);
+ cube = cuddUniqueInter(dd, f->index, DD_ZERO(dd), cuddE(f));
+ } else {
+#ifdef DD_DEBUG
+ assert(!Cudd_IsConstant(t) || t == DD_ONE(dd));
+#endif
+ *distance = -cuddV(cuddE(f));
+ cube = cuddUniqueInter(dd, f->index, t, DD_ZERO(dd));
+ }
+
+ return(cube);
+
+} /* end of separateCube */
+
+
+/**Function********************************************************************
+
+ Synopsis [Builds a result for cache storage.]
+
+ Description [Builds a result for cache storage. Returns a pointer
+ to the resulting ADD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddBddClosestCube separateCube]
+
+******************************************************************************/
+static DdNode *
+createResult(
+ DdManager *dd,
+ unsigned int index,
+ unsigned int phase,
+ DdNode *cube,
+ CUDD_VALUE_TYPE distance)
+{
+ DdNode *res, *constant;
+
+ /* Special case. The cube is either one or zero, and we do not
+ ** add any variables. Hence, the result is also one or zero,
+ ** and the distance remains implied by teh value of the constant. */
+ if (index == CUDD_CONST_INDEX && Cudd_IsConstant(cube)) return(cube);
+
+ constant = cuddUniqueConst(dd,-distance);
+ if (constant == NULL) return(NULL);
+ cuddRef(constant);
+
+ if (index == CUDD_CONST_INDEX) {
+ /* Replace the top node. */
+ if (cuddT(cube) == DD_ZERO(dd)) {
+ res = cuddUniqueInter(dd,cube->index,constant,cuddE(cube));
+ } else {
+ res = cuddUniqueInter(dd,cube->index,cuddT(cube),constant);
+ }
+ } else {
+ /* Add a new top node. */
+#ifdef DD_DEBUG
+ assert(cuddI(dd,index) < cuddI(dd,cube->index));
+#endif
+ if (phase) {
+ res = cuddUniqueInter(dd,index,cube,constant);
+ } else {
+ res = cuddUniqueInter(dd,index,constant,cube);
+ }
+ }
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd, constant);
+ return(NULL);
+ }
+ cuddDeref(constant); /* safe because constant is part of res */
+
+ return(res);
+
+} /* end of createResult */
diff --git a/src/bdd/cudd/cuddRead.c b/src/bdd/cudd/cuddRead.c
new file mode 100644
index 00000000..eea4c7f3
--- /dev/null
+++ b/src/bdd/cudd/cuddRead.c
@@ -0,0 +1,490 @@
+/**CFile***********************************************************************
+
+ FileName [cuddRead.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions to read in a matrix]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_addRead()
+ <li> Cudd_bddRead()
+ </ul>]
+
+ SeeAlso [cudd_addHarwell.c]
+
+ Author [Fabio Somenzi]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddRead.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads in a sparse matrix.]
+
+ Description [Reads in a sparse matrix specified in a simple format.
+ The first line of the input contains the numbers of rows and columns.
+ The remaining lines contain the elements of the matrix, one per line.
+ Given a background value
+ (specified by the background field of the manager), only the values
+ different from it are explicitly listed. Each foreground element is
+ described by two integers, i.e., the row and column number, and a
+ real number, i.e., the value.<p>
+ Cudd_addRead produces an ADD that depends on two sets of variables: x
+ and y. The x variables (x\[0\] ... x\[nx-1\]) encode the row index and
+ the y variables (y\[0\] ... y\[ny-1\]) encode the column index.
+ x\[0\] and y\[0\] are the most significant bits in the indices.
+ The variables may already exist or may be created by the function.
+ The index of x\[i\] is bx+i*sx, and the index of y\[i\] is by+i*sy.<p>
+ On input, nx and ny hold the numbers
+ of row and column variables already in existence. On output, they
+ hold the numbers of row and column variables actually used by the
+ matrix. When Cudd_addRead creates the variable arrays,
+ the index of x\[i\] is bx+i*sx, and the index of y\[i\] is by+i*sy.
+ When some variables already exist Cudd_addRead expects the indices
+ of the existing x variables to be bx+i*sx, and the indices of the
+ existing y variables to be by+i*sy.<p>
+ m and n are set to the numbers of rows and columns of the
+ matrix. Their values on input are immaterial.
+ The ADD for the
+ sparse matrix is returned in E, and its reference count is > 0.
+ Cudd_addRead returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [nx and ny are set to the numbers of row and column
+ variables. m and n are set to the numbers of rows and columns. x and y
+ are possibly extended to represent the array of row and column
+ variables. Similarly for xn and yn_, which hold on return from
+ Cudd_addRead the complements of the row and column variables.]
+
+ SeeAlso [Cudd_addHarwell Cudd_bddRead]
+
+******************************************************************************/
+int
+Cudd_addRead(
+ FILE * fp /* input file pointer */,
+ DdManager * dd /* DD manager */,
+ DdNode ** E /* characteristic function of the graph */,
+ DdNode *** x /* array of row variables */,
+ DdNode *** y /* array of column variables */,
+ DdNode *** xn /* array of complemented row variables */,
+ DdNode *** yn_ /* array of complemented column variables */,
+ int * nx /* number or row variables */,
+ int * ny /* number or column variables */,
+ int * m /* number of rows */,
+ int * n /* number of columns */,
+ int bx /* first index of row variables */,
+ int sx /* step of row variables */,
+ int by /* first index of column variables */,
+ int sy /* step of column variables */)
+{
+ DdNode *one, *zero;
+ DdNode *w, *neW;
+ DdNode *minterm1;
+ int u, v, err, i, nv;
+ int lnx, lny;
+ CUDD_VALUE_TYPE val;
+ DdNode **lx, **ly, **lxn, **lyn;
+
+ one = DD_ONE(dd);
+ zero = DD_ZERO(dd);
+
+ err = fscanf(fp, "%d %d", &u, &v);
+ if (err == EOF) {
+ return(0);
+ } else if (err != 2) {
+ return(0);
+ }
+
+ *m = u;
+ /* Compute the number of x variables. */
+ lx = *x; lxn = *xn;
+ u--; /* row and column numbers start from 0 */
+ for (lnx=0; u > 0; lnx++) {
+ u >>= 1;
+ }
+ /* Here we rely on the fact that REALLOC of a null pointer is
+ ** translates to an ALLOC.
+ */
+ if (lnx > *nx) {
+ *x = lx = REALLOC(DdNode *, *x, lnx);
+ if (lx == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ *xn = lxn = REALLOC(DdNode *, *xn, lnx);
+ if (lxn == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ }
+
+ *n = v;
+ /* Compute the number of y variables. */
+ ly = *y; lyn = *yn_;
+ v--; /* row and column numbers start from 0 */
+ for (lny=0; v > 0; lny++) {
+ v >>= 1;
+ }
+ /* Here we rely on the fact that REALLOC of a null pointer is
+ ** translates to an ALLOC.
+ */
+ if (lny > *ny) {
+ *y = ly = REALLOC(DdNode *, *y, lny);
+ if (ly == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ *yn_ = lyn = REALLOC(DdNode *, *yn_, lny);
+ if (lyn == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ }
+
+ /* Create all new variables. */
+ for (i = *nx, nv = bx + (*nx) * sx; i < lnx; i++, nv += sx) {
+ do {
+ dd->reordered = 0;
+ lx[i] = cuddUniqueInter(dd, nv, one, zero);
+ } while (dd->reordered == 1);
+ if (lx[i] == NULL) return(0);
+ cuddRef(lx[i]);
+ do {
+ dd->reordered = 0;
+ lxn[i] = cuddUniqueInter(dd, nv, zero, one);
+ } while (dd->reordered == 1);
+ if (lxn[i] == NULL) return(0);
+ cuddRef(lxn[i]);
+ }
+ for (i = *ny, nv = by + (*ny) * sy; i < lny; i++, nv += sy) {
+ do {
+ dd->reordered = 0;
+ ly[i] = cuddUniqueInter(dd, nv, one, zero);
+ } while (dd->reordered == 1);
+ if (ly[i] == NULL) return(0);
+ cuddRef(ly[i]);
+ do {
+ dd->reordered = 0;
+ lyn[i] = cuddUniqueInter(dd, nv, zero, one);
+ } while (dd->reordered == 1);
+ if (lyn[i] == NULL) return(0);
+ cuddRef(lyn[i]);
+ }
+ *nx = lnx;
+ *ny = lny;
+
+ *E = dd->background; /* this call will never cause reordering */
+ cuddRef(*E);
+
+ while (! feof(fp)) {
+ err = fscanf(fp, "%d %d %lf", &u, &v, &val);
+ if (err == EOF) {
+ break;
+ } else if (err != 3) {
+ return(0);
+ } else if (u >= *m || v >= *n || u < 0 || v < 0) {
+ return(0);
+ }
+
+ minterm1 = one; cuddRef(minterm1);
+
+ /* Build minterm1 corresponding to this arc */
+ for (i = lnx - 1; i>=0; i--) {
+ if (u & 1) {
+ w = Cudd_addApply(dd, Cudd_addTimes, minterm1, lx[i]);
+ } else {
+ w = Cudd_addApply(dd, Cudd_addTimes, minterm1, lxn[i]);
+ }
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, minterm1);
+ return(0);
+ }
+ cuddRef(w);
+ Cudd_RecursiveDeref(dd, minterm1);
+ minterm1 = w;
+ u >>= 1;
+ }
+ for (i = lny - 1; i>=0; i--) {
+ if (v & 1) {
+ w = Cudd_addApply(dd, Cudd_addTimes, minterm1, ly[i]);
+ } else {
+ w = Cudd_addApply(dd, Cudd_addTimes, minterm1, lyn[i]);
+ }
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, minterm1);
+ return(0);
+ }
+ cuddRef(w);
+ Cudd_RecursiveDeref(dd, minterm1);
+ minterm1 = w;
+ v >>= 1;
+ }
+ /* Create new constant node if necessary.
+ ** This call will never cause reordering.
+ */
+ neW = cuddUniqueConst(dd, val);
+ if (neW == NULL) {
+ Cudd_RecursiveDeref(dd, minterm1);
+ return(0);
+ }
+ cuddRef(neW);
+
+ w = Cudd_addIte(dd, minterm1, neW, *E);
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, minterm1);
+ Cudd_RecursiveDeref(dd, neW);
+ return(0);
+ }
+ cuddRef(w);
+ Cudd_RecursiveDeref(dd, minterm1);
+ Cudd_RecursiveDeref(dd, neW);
+ Cudd_RecursiveDeref(dd, *E);
+ *E = w;
+ }
+ return(1);
+
+} /* end of Cudd_addRead */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads in a graph (without labels) given as a list of arcs.]
+
+ Description [Reads in a graph (without labels) given as an adjacency
+ matrix. The first line of the input contains the numbers of rows and
+ columns of the adjacency matrix. The remaining lines contain the arcs
+ of the graph, one per line. Each arc is described by two integers,
+ i.e., the row and column number, or the indices of the two endpoints.
+ Cudd_bddRead produces a BDD that depends on two sets of variables: x
+ and y. The x variables (x\[0\] ... x\[nx-1\]) encode
+ the row index and the y variables (y\[0\] ... y\[ny-1\]) encode the
+ column index. x\[0\] and y\[0\] are the most significant bits in the
+ indices.
+ The variables may already exist or may be created by the function.
+ The index of x\[i\] is bx+i*sx, and the index of y\[i\] is by+i*sy.<p>
+ On input, nx and ny hold the numbers of row and column variables already
+ in existence. On output, they hold the numbers of row and column
+ variables actually used by the matrix. When Cudd_bddRead creates the
+ variable arrays, the index of x\[i\] is bx+i*sx, and the index of
+ y\[i\] is by+i*sy. When some variables already exist, Cudd_bddRead
+ expects the indices of the existing x variables to be bx+i*sx, and the
+ indices of the existing y variables to be by+i*sy.<p>
+ m and n are set to the numbers of rows and columns of the
+ matrix. Their values on input are immaterial. The BDD for the graph
+ is returned in E, and its reference count is > 0. Cudd_bddRead returns
+ 1 in case of success; 0 otherwise.]
+
+ SideEffects [nx and ny are set to the numbers of row and column
+ variables. m and n are set to the numbers of rows and columns. x and y
+ are possibly extended to represent the array of row and column
+ variables.]
+
+ SeeAlso [Cudd_addHarwell Cudd_addRead]
+
+******************************************************************************/
+int
+Cudd_bddRead(
+ FILE * fp /* input file pointer */,
+ DdManager * dd /* DD manager */,
+ DdNode ** E /* characteristic function of the graph */,
+ DdNode *** x /* array of row variables */,
+ DdNode *** y /* array of column variables */,
+ int * nx /* number or row variables */,
+ int * ny /* number or column variables */,
+ int * m /* number of rows */,
+ int * n /* number of columns */,
+ int bx /* first index of row variables */,
+ int sx /* step of row variables */,
+ int by /* first index of column variables */,
+ int sy /* step of column variables */)
+{
+ DdNode *one, *zero;
+ DdNode *w;
+ DdNode *minterm1;
+ int u, v, err, i, nv;
+ int lnx, lny;
+ DdNode **lx, **ly;
+
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+
+ err = fscanf(fp, "%d %d", &u, &v);
+ if (err == EOF) {
+ return(0);
+ } else if (err != 2) {
+ return(0);
+ }
+
+ *m = u;
+ /* Compute the number of x variables. */
+ lx = *x;
+ u--; /* row and column numbers start from 0 */
+ for (lnx=0; u > 0; lnx++) {
+ u >>= 1;
+ }
+ if (lnx > *nx) {
+ *x = lx = REALLOC(DdNode *, *x, lnx);
+ if (lx == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ }
+
+ *n = v;
+ /* Compute the number of y variables. */
+ ly = *y;
+ v--; /* row and column numbers start from 0 */
+ for (lny=0; v > 0; lny++) {
+ v >>= 1;
+ }
+ if (lny > *ny) {
+ *y = ly = REALLOC(DdNode *, *y, lny);
+ if (ly == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ }
+
+ /* Create all new variables. */
+ for (i = *nx, nv = bx + (*nx) * sx; i < lnx; i++, nv += sx) {
+ do {
+ dd->reordered = 0;
+ lx[i] = cuddUniqueInter(dd, nv, one, zero);
+ } while (dd->reordered == 1);
+ if (lx[i] == NULL) return(0);
+ cuddRef(lx[i]);
+ }
+ for (i = *ny, nv = by + (*ny) * sy; i < lny; i++, nv += sy) {
+ do {
+ dd->reordered = 0;
+ ly[i] = cuddUniqueInter(dd, nv, one, zero);
+ } while (dd->reordered == 1);
+ if (ly[i] == NULL) return(0);
+ cuddRef(ly[i]);
+ }
+ *nx = lnx;
+ *ny = lny;
+
+ *E = zero; /* this call will never cause reordering */
+ cuddRef(*E);
+
+ while (! feof(fp)) {
+ err = fscanf(fp, "%d %d", &u, &v);
+ if (err == EOF) {
+ break;
+ } else if (err != 2) {
+ return(0);
+ } else if (u >= *m || v >= *n || u < 0 || v < 0) {
+ return(0);
+ }
+
+ minterm1 = one; cuddRef(minterm1);
+
+ /* Build minterm1 corresponding to this arc. */
+ for (i = lnx - 1; i>=0; i--) {
+ if (u & 1) {
+ w = Cudd_bddAnd(dd, minterm1, lx[i]);
+ } else {
+ w = Cudd_bddAnd(dd, minterm1, Cudd_Not(lx[i]));
+ }
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, minterm1);
+ return(0);
+ }
+ cuddRef(w);
+ Cudd_RecursiveDeref(dd,minterm1);
+ minterm1 = w;
+ u >>= 1;
+ }
+ for (i = lny - 1; i>=0; i--) {
+ if (v & 1) {
+ w = Cudd_bddAnd(dd, minterm1, ly[i]);
+ } else {
+ w = Cudd_bddAnd(dd, minterm1, Cudd_Not(ly[i]));
+ }
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, minterm1);
+ return(0);
+ }
+ cuddRef(w);
+ Cudd_RecursiveDeref(dd, minterm1);
+ minterm1 = w;
+ v >>= 1;
+ }
+
+ w = Cudd_bddAnd(dd, Cudd_Not(minterm1), Cudd_Not(*E));
+ if (w == NULL) {
+ Cudd_RecursiveDeref(dd, minterm1);
+ return(0);
+ }
+ w = Cudd_Not(w);
+ cuddRef(w);
+ Cudd_RecursiveDeref(dd, minterm1);
+ Cudd_RecursiveDeref(dd, *E);
+ *E = w;
+ }
+ return(1);
+
+} /* end of Cudd_bddRead */
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
diff --git a/src/bdd/cudd/cuddRef.c b/src/bdd/cudd/cuddRef.c
new file mode 100644
index 00000000..af08d048
--- /dev/null
+++ b/src/bdd/cudd/cuddRef.c
@@ -0,0 +1,781 @@
+/**CFile***********************************************************************
+
+ FileName [cuddRef.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions that manipulate the reference counts.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_Ref()
+ <li> Cudd_RecursiveDeref()
+ <li> Cudd_IterDerefBdd()
+ <li> Cudd_DelayedDerefBdd()
+ <li> Cudd_RecursiveDerefZdd()
+ <li> Cudd_Deref()
+ <li> Cudd_CheckZeroRef()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddReclaim()
+ <li> cuddReclaimZdd()
+ <li> cuddClearDeathRow()
+ <li> cuddShrinkDeathRow()
+ <li> cuddIsInDeathRow()
+ <li> cuddTimesInDeathRow()
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddRef.c,v 1.1.1.1 2003/02/24 22:23:53 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Increases the reference count of a node, if it is not
+ saturated.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_RecursiveDeref Cudd_Deref]
+
+******************************************************************************/
+void
+Cudd_Ref(
+ DdNode * n)
+{
+
+ n = Cudd_Regular(n);
+
+ cuddSatInc(n->ref);
+
+} /* end of Cudd_Ref */
+
+
+/**Function********************************************************************
+
+ Synopsis [Decreases the reference count of node n.]
+
+ Description [Decreases the reference count of node n. If n dies,
+ recursively decreases the reference counts of its children. It is
+ used to dispose of a DD that is no longer needed.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Deref Cudd_Ref Cudd_RecursiveDerefZdd]
+
+******************************************************************************/
+void
+Cudd_RecursiveDeref(
+ DdManager * table,
+ DdNode * n)
+{
+ DdNode *N;
+ int ord;
+ DdNodePtr *stack = table->stack;
+ int SP = 1;
+
+ unsigned int live = table->keys - table->dead;
+ if (live > table->peakLiveNodes) {
+ table->peakLiveNodes = live;
+ }
+
+ N = Cudd_Regular(n);
+
+ do {
+#ifdef DD_DEBUG
+ assert(N->ref != 0);
+#endif
+
+ if (N->ref == 1) {
+ N->ref = 0;
+ table->dead++;
+#ifdef DD_STATS
+ table->nodesDropped++;
+#endif
+ if (cuddIsConstant(N)) {
+ table->constants.dead++;
+ N = stack[--SP];
+ } else {
+ ord = table->perm[N->index];
+ stack[SP++] = Cudd_Regular(cuddE(N));
+ table->subtables[ord].dead++;
+ N = cuddT(N);
+ }
+ } else {
+ cuddSatDec(N->ref);
+ N = stack[--SP];
+ }
+ } while (SP != 0);
+
+} /* end of Cudd_RecursiveDeref */
+
+
+/**Function********************************************************************
+
+ Synopsis [Decreases the reference count of BDD node n.]
+
+ Description [Decreases the reference count of node n. If n dies,
+ recursively decreases the reference counts of its children. It is
+ used to dispose of a BDD that is no longer needed. It is more
+ efficient than Cudd_RecursiveDeref, but it cannot be used on
+ ADDs. The greater efficiency comes from being able to assume that no
+ constant node will ever die as a result of a call to this
+ procedure.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_RecursiveDeref Cudd_DelayedDerefBdd]
+
+******************************************************************************/
+void
+Cudd_IterDerefBdd(
+ DdManager * table,
+ DdNode * n)
+{
+ DdNode *N;
+ int ord;
+ DdNodePtr *stack = table->stack;
+ int SP = 1;
+
+ unsigned int live = table->keys - table->dead;
+ if (live > table->peakLiveNodes) {
+ table->peakLiveNodes = live;
+ }
+
+ N = Cudd_Regular(n);
+
+ do {
+#ifdef DD_DEBUG
+ assert(N->ref != 0);
+#endif
+
+ if (N->ref == 1) {
+ N->ref = 0;
+ table->dead++;
+#ifdef DD_STATS
+ table->nodesDropped++;
+#endif
+ ord = table->perm[N->index];
+ stack[SP++] = Cudd_Regular(cuddE(N));
+ table->subtables[ord].dead++;
+ N = cuddT(N);
+ } else {
+ cuddSatDec(N->ref);
+ N = stack[--SP];
+ }
+ } while (SP != 0);
+
+} /* end of Cudd_IterDerefBdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Decreases the reference count of BDD node n.]
+
+ Description [Enqueues node n for later dereferencing. If the queue
+ is full decreases the reference count of the oldest node N to make
+ room for n. If N dies, recursively decreases the reference counts of
+ its children. It is used to dispose of a BDD that is currently not
+ needed, but may be useful again in the near future. The dereferencing
+ proper is done as in Cudd_IterDerefBdd.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_RecursiveDeref Cudd_IterDerefBdd]
+
+******************************************************************************/
+void
+Cudd_DelayedDerefBdd(
+ DdManager * table,
+ DdNode * n)
+{
+ DdNode *N;
+ int ord;
+ DdNodePtr *stack;
+ int SP;
+
+ unsigned int live = table->keys - table->dead;
+ if (live > table->peakLiveNodes) {
+ table->peakLiveNodes = live;
+ }
+
+ n = Cudd_Regular(n);
+#ifdef DD_DEBUG
+ assert(n->ref != 0);
+#endif
+
+#ifdef DD_NO_DEATH_ROW
+ N = n;
+#else
+ if (cuddIsConstant(n) || n->ref > 1) {
+#ifdef DD_DEBUG
+ assert(n->ref != 1 && (!cuddIsConstant(n) || n == DD_ONE(table)));
+#endif
+ cuddSatDec(n->ref);
+ return;
+ }
+
+ N = table->deathRow[table->nextDead];
+
+ if (N != NULL) {
+#endif
+#ifdef DD_DEBUG
+ assert(!Cudd_IsComplement(N));
+#endif
+ stack = table->stack;
+ SP = 1;
+ do {
+#ifdef DD_DEBUG
+ assert(N->ref != 0);
+#endif
+ if (N->ref == 1) {
+ N->ref = 0;
+ table->dead++;
+#ifdef DD_STATS
+ table->nodesDropped++;
+#endif
+ ord = table->perm[N->index];
+ stack[SP++] = Cudd_Regular(cuddE(N));
+ table->subtables[ord].dead++;
+ N = cuddT(N);
+ } else {
+ cuddSatDec(N->ref);
+ N = stack[--SP];
+ }
+ } while (SP != 0);
+#ifndef DD_NO_DEATH_ROW
+ }
+ table->deathRow[table->nextDead] = n;
+
+ /* Udate insertion point. */
+ table->nextDead++;
+ table->nextDead &= table->deadMask;
+#if 0
+ if (table->nextDead == table->deathRowDepth) {
+ if (table->deathRowDepth < table->looseUpTo / 2) {
+ extern void (*MMoutOfMemory)(long);
+ void (*saveHandler)(long) = MMoutOfMemory;
+ DdNodePtr *newRow;
+ MMoutOfMemory = Cudd_OutOfMem;
+ newRow = REALLOC(DdNodePtr,table->deathRow,2*table->deathRowDepth);
+ MMoutOfMemory = saveHandler;
+ if (newRow == NULL) {
+ table->nextDead = 0;
+ } else {
+ int i;
+ table->memused += table->deathRowDepth;
+ i = table->deathRowDepth;
+ table->deathRowDepth <<= 1;
+ for (; i < table->deathRowDepth; i++) {
+ newRow[i] = NULL;
+ }
+ table->deadMask = table->deathRowDepth - 1;
+ table->deathRow = newRow;
+ }
+ } else {
+ table->nextDead = 0;
+ }
+ }
+#endif
+#endif
+
+} /* end of Cudd_DelayedDerefBdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Decreases the reference count of ZDD node n.]
+
+ Description [Decreases the reference count of ZDD node n. If n dies,
+ recursively decreases the reference counts of its children. It is
+ used to dispose of a ZDD that is no longer needed.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Deref Cudd_Ref Cudd_RecursiveDeref]
+
+******************************************************************************/
+void
+Cudd_RecursiveDerefZdd(
+ DdManager * table,
+ DdNode * n)
+{
+ DdNode *N;
+ int ord;
+ DdNodePtr *stack = table->stack;
+ int SP = 1;
+
+ N = n;
+
+ do {
+#ifdef DD_DEBUG
+ assert(N->ref != 0);
+#endif
+
+ cuddSatDec(N->ref);
+
+ if (N->ref == 0) {
+ table->deadZ++;
+#ifdef DD_STATS
+ table->nodesDropped++;
+#endif
+#ifdef DD_DEBUG
+ assert(!cuddIsConstant(N));
+#endif
+ ord = table->permZ[N->index];
+ stack[SP++] = cuddE(N);
+ table->subtableZ[ord].dead++;
+ N = cuddT(N);
+ } else {
+ N = stack[--SP];
+ }
+ } while (SP != 0);
+
+} /* end of Cudd_RecursiveDerefZdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Decreases the reference count of node.]
+
+ Description [Decreases the reference count of node. It is primarily
+ used in recursive procedures to decrease the ref count of a result
+ node before returning it. This accomplishes the goal of removing the
+ protection applied by a previous Cudd_Ref.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_RecursiveDeref Cudd_RecursiveDerefZdd Cudd_Ref]
+
+******************************************************************************/
+void
+Cudd_Deref(
+ DdNode * node)
+{
+ node = Cudd_Regular(node);
+ cuddSatDec(node->ref);
+
+} /* end of Cudd_Deref */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks the unique table for nodes with non-zero reference
+ counts.]
+
+ Description [Checks the unique table for nodes with non-zero
+ reference counts. It is normally called before Cudd_Quit to make sure
+ that there are no memory leaks due to missing Cudd_RecursiveDeref's.
+ Takes into account that reference counts may saturate and that the
+ basic constants and the projection functions are referenced by the
+ manager. Returns the number of nodes with non-zero reference count.
+ (Except for the cases mentioned above.)]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+Cudd_CheckZeroRef(
+ DdManager * manager)
+{
+ int size;
+ int i, j;
+ int remain; /* the expected number of remaining references to one */
+ DdNodePtr *nodelist;
+ DdNode *node;
+ DdNode *sentinel = &(manager->sentinel);
+ DdSubtable *subtable;
+ int count = 0;
+ int index;
+
+#ifndef DD_NO_DEATH_ROW
+ cuddClearDeathRow(manager);
+#endif
+
+ /* First look at the BDD/ADD subtables. */
+ remain = 1; /* reference from the manager */
+ size = manager->size;
+ remain += 2 * size; /* reference from the BDD projection functions */
+
+ for (i = 0; i < size; i++) {
+ subtable = &(manager->subtables[i]);
+ nodelist = subtable->nodelist;
+ for (j = 0; (unsigned) j < subtable->slots; j++) {
+ node = nodelist[j];
+ while (node != sentinel) {
+ if (node->ref != 0 && node->ref != DD_MAXREF) {
+ index = (int) node->index;
+ if (node != manager->vars[index]) {
+ count++;
+ } else {
+ if (node->ref != 1) {
+ count++;
+ }
+ }
+ }
+ node = node->next;
+ }
+ }
+ }
+
+ /* Then look at the ZDD subtables. */
+ size = manager->sizeZ;
+ if (size) /* references from ZDD universe */
+ remain += 2;
+
+ for (i = 0; i < size; i++) {
+ subtable = &(manager->subtableZ[i]);
+ nodelist = subtable->nodelist;
+ for (j = 0; (unsigned) j < subtable->slots; j++) {
+ node = nodelist[j];
+ while (node != NULL) {
+ if (node->ref != 0 && node->ref != DD_MAXREF) {
+ index = (int) node->index;
+ if (node == manager->univ[manager->permZ[index]]) {
+ if (node->ref > 2) {
+ count++;
+ }
+ } else {
+ count++;
+ }
+ }
+ node = node->next;
+ }
+ }
+ }
+
+ /* Now examine the constant table. Plusinfinity, minusinfinity, and
+ ** zero are referenced by the manager. One is referenced by the
+ ** manager, by the ZDD universe, and by all projection functions.
+ ** All other nodes should have no references.
+ */
+ nodelist = manager->constants.nodelist;
+ for (j = 0; (unsigned) j < manager->constants.slots; j++) {
+ node = nodelist[j];
+ while (node != NULL) {
+ if (node->ref != 0 && node->ref != DD_MAXREF) {
+ if (node == manager->one) {
+ if ((int) node->ref != remain) {
+ count++;
+ }
+ } else if (node == manager->zero ||
+ node == manager->plusinfinity ||
+ node == manager->minusinfinity) {
+ if (node->ref != 1) {
+ count++;
+ }
+ } else {
+ count++;
+ }
+ }
+ node = node->next;
+ }
+ }
+ return(count);
+
+} /* end of Cudd_CheckZeroRef */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Brings children of a dead node back.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [cuddReclaimZdd]
+
+******************************************************************************/
+void
+cuddReclaim(
+ DdManager * table,
+ DdNode * n)
+{
+ DdNode *N;
+ int ord;
+ DdNodePtr *stack = table->stack;
+ int SP = 1;
+ double initialDead = table->dead;
+
+ N = Cudd_Regular(n);
+
+#ifdef DD_DEBUG
+ assert(N->ref == 0);
+#endif
+
+ do {
+ if (N->ref == 0) {
+ N->ref = 1;
+ table->dead--;
+ if (cuddIsConstant(N)) {
+ table->constants.dead--;
+ N = stack[--SP];
+ } else {
+ ord = table->perm[N->index];
+ stack[SP++] = Cudd_Regular(cuddE(N));
+ table->subtables[ord].dead--;
+ N = cuddT(N);
+ }
+ } else {
+ cuddSatInc(N->ref);
+ N = stack[--SP];
+ }
+ } while (SP != 0);
+
+ N = Cudd_Regular(n);
+ cuddSatDec(N->ref);
+ table->reclaimed += initialDead - table->dead;
+
+} /* end of cuddReclaim */
+
+
+/**Function********************************************************************
+
+ Synopsis [Brings children of a dead ZDD node back.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [cuddReclaim]
+
+******************************************************************************/
+void
+cuddReclaimZdd(
+ DdManager * table,
+ DdNode * n)
+{
+ DdNode *N;
+ int ord;
+ DdNodePtr *stack = table->stack;
+ int SP = 1;
+
+ N = n;
+
+#ifdef DD_DEBUG
+ assert(N->ref == 0);
+#endif
+
+ do {
+ cuddSatInc(N->ref);
+
+ if (N->ref == 1) {
+ table->deadZ--;
+ table->reclaimed++;
+#ifdef DD_DEBUG
+ assert(!cuddIsConstant(N));
+#endif
+ ord = table->permZ[N->index];
+ stack[SP++] = cuddE(N);
+ table->subtableZ[ord].dead--;
+ N = cuddT(N);
+ } else {
+ N = stack[--SP];
+ }
+ } while (SP != 0);
+
+ cuddSatDec(n->ref);
+
+} /* end of cuddReclaimZdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Shrinks the death row.]
+
+ Description [Shrinks the death row by a factor of four.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddClearDeathRow]
+
+******************************************************************************/
+void
+cuddShrinkDeathRow(
+ DdManager *table)
+{
+#ifndef DD_NO_DEATH_ROW
+ int i;
+
+ if (table->deathRowDepth > 3) {
+ for (i = table->deathRowDepth/4; i < table->deathRowDepth; i++) {
+ if (table->deathRow[i] == NULL) break;
+ Cudd_IterDerefBdd(table,table->deathRow[i]);
+ table->deathRow[i] = NULL;
+ }
+ table->deathRowDepth /= 4;
+ table->deadMask = table->deathRowDepth - 2;
+ if ((unsigned) table->nextDead > table->deadMask) {
+ table->nextDead = 0;
+ }
+ table->deathRow = REALLOC(DdNodePtr, table->deathRow,
+ table->deathRowDepth);
+ }
+#endif
+
+} /* end of cuddShrinkDeathRow */
+
+
+/**Function********************************************************************
+
+ Synopsis [Clears the death row.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DelayedDerefBdd Cudd_IterDerefBdd Cudd_CheckZeroRef
+ cuddGarbageCollect]
+
+******************************************************************************/
+void
+cuddClearDeathRow(
+ DdManager *table)
+{
+#ifndef DD_NO_DEATH_ROW
+ int i;
+
+ for (i = 0; i < table->deathRowDepth; i++) {
+ if (table->deathRow[i] == NULL) break;
+ Cudd_IterDerefBdd(table,table->deathRow[i]);
+ table->deathRow[i] = NULL;
+ }
+#ifdef DD_DEBUG
+ for (; i < table->deathRowDepth; i++) {
+ assert(table->deathRow[i] == NULL);
+ }
+#endif
+ table->nextDead = 0;
+#endif
+
+} /* end of cuddClearDeathRow */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether a node is in the death row.]
+
+ Description [Checks whether a node is in the death row. Returns the
+ position of the first occurrence if the node is present; -1
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DelayedDerefBdd cuddClearDeathRow]
+
+******************************************************************************/
+int
+cuddIsInDeathRow(
+ DdManager *dd,
+ DdNode *f)
+{
+#ifndef DD_NO_DEATH_ROW
+ int i;
+
+ for (i = 0; i < dd->deathRowDepth; i++) {
+ if (f == dd->deathRow[i]) {
+ return(i);
+ }
+ }
+#endif
+
+ return(-1);
+
+} /* end of cuddIsInDeathRow */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts how many times a node is in the death row.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DelayedDerefBdd cuddClearDeathRow cuddIsInDeathRow]
+
+******************************************************************************/
+int
+cuddTimesInDeathRow(
+ DdManager *dd,
+ DdNode *f)
+{
+ int count = 0;
+#ifndef DD_NO_DEATH_ROW
+ int i;
+
+ for (i = 0; i < dd->deathRowDepth; i++) {
+ count += f == dd->deathRow[i];
+ }
+#endif
+
+ return(count);
+
+} /* end of cuddTimesInDeathRow */
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
diff --git a/src/bdd/cudd/cuddReorder.c b/src/bdd/cudd/cuddReorder.c
new file mode 100644
index 00000000..e2b3470b
--- /dev/null
+++ b/src/bdd/cudd/cuddReorder.c
@@ -0,0 +1,2090 @@
+/**CFile***********************************************************************
+
+ FileName [cuddReorder.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions for dynamic variable reordering.]
+
+ Description [External procedures included in this file:
+ <ul>
+ <li> Cudd_ReduceHeap()
+ <li> Cudd_ShuffleHeap()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddDynamicAllocNode()
+ <li> cuddSifting()
+ <li> cuddSwapping()
+ <li> cuddNextHigh()
+ <li> cuddNextLow()
+ <li> cuddSwapInPlace()
+ <li> cuddBddAlignToZdd()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> ddUniqueCompare()
+ <li> ddSwapAny()
+ <li> ddSiftingAux()
+ <li> ddSiftingUp()
+ <li> ddSiftingDown()
+ <li> ddSiftingBackward()
+ <li> ddReorderPreprocess()
+ <li> ddReorderPostprocess()
+ <li> ddShuffle()
+ <li> ddSiftUp()
+ <li> bddFixTree()
+ </ul>]
+
+ Author [Shipra Panda, Bernard Plessier, Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define DD_MAX_SUBTABLE_SPARSITY 8
+#define DD_SHRINK_FACTOR 2
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddReorder.c,v 1.1.1.1 2003/02/24 22:23:53 wjiang Exp $";
+#endif
+
+static int *entry;
+
+int ddTotalNumberSwapping;
+#ifdef DD_STATS
+int ddTotalNISwaps;
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int ddUniqueCompare ARGS((int *ptrX, int *ptrY));
+static Move * ddSwapAny ARGS((DdManager *table, int x, int y));
+static int ddSiftingAux ARGS((DdManager *table, int x, int xLow, int xHigh));
+static Move * ddSiftingUp ARGS((DdManager *table, int y, int xLow));
+static Move * ddSiftingDown ARGS((DdManager *table, int x, int xHigh));
+static int ddSiftingBackward ARGS((DdManager *table, int size, Move *moves));
+static int ddReorderPreprocess ARGS((DdManager *table));
+static int ddReorderPostprocess ARGS((DdManager *table));
+static int ddShuffle ARGS((DdManager *table, int *permutation));
+static int ddSiftUp ARGS((DdManager *table, int x, int xLow));
+static void bddFixTree ARGS((DdManager *table, MtrNode *treenode));
+static int ddUpdateMtrTree ARGS((DdManager *table, MtrNode *treenode, int *perm, int *invperm));
+static int ddCheckPermuation ARGS((DdManager *table, MtrNode *treenode, int *perm, int *invperm));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Main dynamic reordering routine.]
+
+ Description [Main dynamic reordering routine.
+ Calls one of the possible reordering procedures:
+ <ul>
+ <li>Swapping
+ <li>Sifting
+ <li>Symmetric Sifting
+ <li>Group Sifting
+ <li>Window Permutation
+ <li>Simulated Annealing
+ <li>Genetic Algorithm
+ <li>Dynamic Programming (exact)
+ </ul>
+
+ For sifting, symmetric sifting, group sifting, and window
+ permutation it is possible to request reordering to convergence.<p>
+
+ The core of all methods is the reordering procedure
+ cuddSwapInPlace() which swaps two adjacent variables and is based
+ on Rudell's paper.
+ Returns 1 in case of success; 0 otherwise. In the case of symmetric
+ sifting (with and without convergence) returns 1 plus the number of
+ symmetric variables, in case of success.]
+
+ SideEffects [Changes the variable order for all diagrams and clears
+ the cache.]
+
+******************************************************************************/
+int
+Cudd_ReduceHeap(
+ DdManager * table /* DD manager */,
+ Cudd_ReorderingType heuristic /* method used for reordering */,
+ int minsize /* bound below which no reordering occurs */)
+{
+ DdHook *hook;
+ int result;
+ unsigned int nextDyn;
+#ifdef DD_STATS
+ unsigned int initialSize;
+ unsigned int finalSize;
+#endif
+ long localTime;
+
+ /* Don't reorder if there are too many dead nodes. */
+ if (table->keys - table->dead < (unsigned) minsize)
+ return(1);
+
+ if (heuristic == CUDD_REORDER_SAME) {
+ heuristic = table->autoMethod;
+ }
+ if (heuristic == CUDD_REORDER_NONE) {
+ return(1);
+ }
+
+ /* This call to Cudd_ReduceHeap does initiate reordering. Therefore
+ ** we count it.
+ */
+ table->reorderings++;
+
+ localTime = util_cpu_time();
+
+ /* Run the hook functions. */
+ hook = table->preReorderingHook;
+ while (hook != NULL) {
+ int res = (hook->f)(table, "BDD", (void *)heuristic);
+ if (res == 0) return(0);
+ hook = hook->next;
+ }
+
+ if (!ddReorderPreprocess(table)) return(0);
+ ddTotalNumberSwapping = 0;
+
+ if (table->keys > table->peakLiveNodes) {
+ table->peakLiveNodes = table->keys;
+ }
+#ifdef DD_STATS
+ initialSize = table->keys - table->isolated;
+ ddTotalNISwaps = 0;
+
+ switch(heuristic) {
+ case CUDD_REORDER_RANDOM:
+ case CUDD_REORDER_RANDOM_PIVOT:
+ (void) fprintf(table->out,"#:I_RANDOM ");
+ break;
+ case CUDD_REORDER_SIFT:
+ case CUDD_REORDER_SIFT_CONVERGE:
+ case CUDD_REORDER_SYMM_SIFT:
+ case CUDD_REORDER_SYMM_SIFT_CONV:
+ case CUDD_REORDER_GROUP_SIFT:
+ case CUDD_REORDER_GROUP_SIFT_CONV:
+ (void) fprintf(table->out,"#:I_SIFTING ");
+ break;
+ case CUDD_REORDER_WINDOW2:
+ case CUDD_REORDER_WINDOW3:
+ case CUDD_REORDER_WINDOW4:
+ case CUDD_REORDER_WINDOW2_CONV:
+ case CUDD_REORDER_WINDOW3_CONV:
+ case CUDD_REORDER_WINDOW4_CONV:
+ (void) fprintf(table->out,"#:I_WINDOW ");
+ break;
+ case CUDD_REORDER_ANNEALING:
+ (void) fprintf(table->out,"#:I_ANNEAL ");
+ break;
+ case CUDD_REORDER_GENETIC:
+ (void) fprintf(table->out,"#:I_GENETIC ");
+ break;
+ case CUDD_REORDER_LINEAR:
+ case CUDD_REORDER_LINEAR_CONVERGE:
+ (void) fprintf(table->out,"#:I_LINSIFT ");
+ break;
+ case CUDD_REORDER_EXACT:
+ (void) fprintf(table->out,"#:I_EXACT ");
+ break;
+ default:
+ return(0);
+ }
+ (void) fprintf(table->out,"%8d: initial size",initialSize);
+#endif
+
+ /* See if we should use alternate threshold for maximum growth. */
+ if (table->reordCycle && table->reorderings % table->reordCycle == 0) {
+ double saveGrowth = table->maxGrowth;
+ table->maxGrowth = table->maxGrowthAlt;
+ result = cuddTreeSifting(table,heuristic);
+ table->maxGrowth = saveGrowth;
+ } else {
+ result = cuddTreeSifting(table,heuristic);
+ }
+
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\n");
+ finalSize = table->keys - table->isolated;
+ (void) fprintf(table->out,"#:F_REORDER %8d: final size\n",finalSize);
+ (void) fprintf(table->out,"#:T_REORDER %8g: total time (sec)\n",
+ ((double)(util_cpu_time() - localTime)/1000.0));
+ (void) fprintf(table->out,"#:N_REORDER %8d: total swaps\n",
+ ddTotalNumberSwapping);
+ (void) fprintf(table->out,"#:M_REORDER %8d: NI swaps\n",ddTotalNISwaps);
+#endif
+
+ if (result == 0)
+ return(0);
+
+ if (!ddReorderPostprocess(table))
+ return(0);
+
+ if (table->realign) {
+ if (!cuddZddAlignToBdd(table))
+ return(0);
+ }
+
+ nextDyn = (table->keys - table->constants.keys + 1) *
+ DD_DYN_RATIO + table->constants.keys;
+ if (table->reorderings < 20 || nextDyn > table->nextDyn)
+ table->nextDyn = nextDyn;
+ else
+ table->nextDyn += 20;
+ table->reordered = 1;
+
+ /* Run hook functions. */
+ hook = table->postReorderingHook;
+ while (hook != NULL) {
+ int res = (hook->f)(table, "BDD", (void *)localTime);
+ if (res == 0) return(0);
+ hook = hook->next;
+ }
+ /* Update cumulative reordering time. */
+ table->reordTime += util_cpu_time() - localTime;
+
+ return(result);
+
+} /* end of Cudd_ReduceHeap */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders variables according to given permutation.]
+
+ Description [Reorders variables according to given permutation.
+ The i-th entry of the permutation array contains the index of the variable
+ that should be brought to the i-th level. The size of the array should be
+ equal or greater to the number of variables currently in use.
+ Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [Changes the variable order for all diagrams and clears
+ the cache.]
+
+ SeeAlso [Cudd_ReduceHeap]
+
+******************************************************************************/
+int
+Cudd_ShuffleHeap(
+ DdManager * table /* DD manager */,
+ int * permutation /* required variable permutation */)
+{
+
+ int result;
+ int i;
+ int identity = 1;
+ int *perm;
+
+ /* Don't waste time in case of identity permutation. */
+ for (i = 0; i < table->size; i++) {
+ if (permutation[i] != table->invperm[i]) {
+ identity = 0;
+ break;
+ }
+ }
+ if (identity == 1) {
+ return(1);
+ }
+ if (!ddReorderPreprocess(table)) return(0);
+ if (table->keys > table->peakLiveNodes) {
+ table->peakLiveNodes = table->keys;
+ }
+
+ perm = ALLOC(int, table->size);
+ for (i = 0; i < table->size; i++)
+ perm[permutation[i]] = i;
+ if (!ddCheckPermuation(table,table->tree,perm,permutation)) {
+ FREE(perm);
+ return(0);
+ }
+ if (!ddUpdateMtrTree(table,table->tree,perm,permutation)) {
+ FREE(perm);
+ return(0);
+ }
+ FREE(perm);
+
+ result = ddShuffle(table,permutation);
+
+ if (!ddReorderPostprocess(table)) return(0);
+
+ return(result);
+
+} /* end of Cudd_ShuffleHeap */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Dynamically allocates a Node.]
+
+ Description [Dynamically allocates a Node. This procedure is similar
+ to cuddAllocNode in Cudd_Table.c, but it does not attempt garbage
+ collection, because during reordering there are no dead nodes.
+ Returns a pointer to a new node if successful; NULL is memory is
+ full.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddAllocNode]
+
+******************************************************************************/
+DdNode *
+cuddDynamicAllocNode(
+ DdManager * table)
+{
+ int i;
+ DdNodePtr *mem;
+ DdNode *list, *node;
+ extern void (*MMoutOfMemory)(long);
+ void (*saveHandler)(long);
+
+ if (table->nextFree == NULL) { /* free list is empty */
+ /* Try to allocate a new block. */
+ saveHandler = MMoutOfMemory;
+ MMoutOfMemory = Cudd_OutOfMem;
+ mem = (DdNodePtr *) ALLOC(DdNode, DD_MEM_CHUNK + 1);
+ MMoutOfMemory = saveHandler;
+ if (mem == NULL && table->stash != NULL) {
+ FREE(table->stash);
+ table->stash = NULL;
+ /* Inhibit resizing of tables. */
+ table->maxCacheHard = table->cacheSlots - 1;
+ table->cacheSlack = -(table->cacheSlots + 1);
+ for (i = 0; i < table->size; i++) {
+ table->subtables[i].maxKeys <<= 2;
+ }
+ mem = (DdNodePtr *) ALLOC(DdNode,DD_MEM_CHUNK + 1);
+ }
+ if (mem == NULL) {
+ /* Out of luck. Call the default handler to do
+ ** whatever it specifies for a failed malloc. If this
+ ** handler returns, then set error code, print
+ ** warning, and return. */
+ (*MMoutOfMemory)(sizeof(DdNode)*(DD_MEM_CHUNK + 1));
+ table->errorCode = CUDD_MEMORY_OUT;
+#ifdef DD_VERBOSE
+ (void) fprintf(table->err,
+ "cuddDynamicAllocNode: out of memory");
+ (void) fprintf(table->err,"Memory in use = %ld\n",
+ table->memused);
+#endif
+ return(NULL);
+ } else { /* successful allocation; slice memory */
+ unsigned long offset;
+ table->memused += (DD_MEM_CHUNK + 1) * sizeof(DdNode);
+ mem[0] = (DdNode *) table->memoryList;
+ table->memoryList = mem;
+
+ /* Here we rely on the fact that the size of a DdNode is a
+ ** power of 2 and a multiple of the size of a pointer.
+ ** If we align one node, all the others will be aligned
+ ** as well. */
+ offset = (unsigned long) mem & (sizeof(DdNode) - 1);
+ mem += (sizeof(DdNode) - offset) / sizeof(DdNodePtr);
+#ifdef DD_DEBUG
+ assert(((unsigned long) mem & (sizeof(DdNode) - 1)) == 0);
+#endif
+ list = (DdNode *) mem;
+
+ i = 1;
+ do {
+ list[i - 1].next = &list[i];
+ } while (++i < DD_MEM_CHUNK);
+
+ list[DD_MEM_CHUNK - 1].next = NULL;
+
+ table->nextFree = &list[0];
+ }
+ } /* if free list empty */
+
+ node = table->nextFree;
+ table->nextFree = node->next;
+ return (node);
+
+} /* end of cuddDynamicAllocNode */
+
+
+/**Function********************************************************************
+
+ Synopsis [Implementation of Rudell's sifting algorithm.]
+
+ Description [Implementation of Rudell's sifting algorithm.
+ Assumes that no dead nodes are present.
+ <ol>
+ <li> Order all the variables according to the number of entries
+ in each unique table.
+ <li> Sift the variable up and down, remembering each time the
+ total size of the DD heap.
+ <li> Select the best permutation.
+ <li> Repeat 3 and 4 for all variables.
+ </ol>
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+int
+cuddSifting(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int i;
+ int *var;
+ int size;
+ int x;
+ int result;
+#ifdef DD_STATS
+ int previousSize;
+#endif
+
+ size = table->size;
+
+ /* Find order in which to sift variables. */
+ var = NULL;
+ entry = ALLOC(int,size);
+ if (entry == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto cuddSiftingOutOfMem;
+ }
+ var = ALLOC(int,size);
+ if (var == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto cuddSiftingOutOfMem;
+ }
+
+ for (i = 0; i < size; i++) {
+ x = table->perm[i];
+ entry[i] = table->subtables[x].keys;
+ var[i] = i;
+ }
+
+ qsort((void *)var,size,sizeof(int),(int (*)(const void *, const void *))ddUniqueCompare);
+
+ /* Now sift. */
+ for (i = 0; i < ddMin(table->siftMaxVar,size); i++) {
+ if (ddTotalNumberSwapping >= table->siftMaxSwap)
+ break;
+ x = table->perm[var[i]];
+
+ if (x < lower || x > upper || table->subtables[x].bindVar == 1)
+ continue;
+#ifdef DD_STATS
+ previousSize = table->keys - table->isolated;
+#endif
+ result = ddSiftingAux(table, x, lower, upper);
+ if (!result) goto cuddSiftingOutOfMem;
+#ifdef DD_STATS
+ if (table->keys < (unsigned) previousSize + table->isolated) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keys > (unsigned) previousSize + table->isolated) {
+ (void) fprintf(table->out,"+"); /* should never happen */
+ (void) fprintf(table->err,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keys - table->isolated, var[i]);
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+
+ FREE(var);
+ FREE(entry);
+
+ return(1);
+
+cuddSiftingOutOfMem:
+
+ if (entry != NULL) FREE(entry);
+ if (var != NULL) FREE(var);
+
+ return(0);
+
+} /* end of cuddSifting */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders variables by a sequence of (non-adjacent) swaps.]
+
+ Description [Implementation of Plessier's algorithm that reorders
+ variables by a sequence of (non-adjacent) swaps.
+ <ol>
+ <li> Select two variables (RANDOM or HEURISTIC).
+ <li> Permute these variables.
+ <li> If the nodes have decreased accept the permutation.
+ <li> Otherwise reconstruct the original heap.
+ <li> Loop.
+ </ol>
+ Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+int
+cuddSwapping(
+ DdManager * table,
+ int lower,
+ int upper,
+ Cudd_ReorderingType heuristic)
+{
+ int i, j;
+ int max, keys;
+ int nvars;
+ int x, y;
+ int iterate;
+ int previousSize;
+ Move *moves, *move;
+ int pivot;
+ int modulo;
+ int result;
+
+#ifdef DD_DEBUG
+ /* Sanity check */
+ assert(lower >= 0 && upper < table->size && lower <= upper);
+#endif
+
+ nvars = upper - lower + 1;
+ iterate = nvars;
+
+ for (i = 0; i < iterate; i++) {
+ if (ddTotalNumberSwapping >= table->siftMaxSwap)
+ break;
+ if (heuristic == CUDD_REORDER_RANDOM_PIVOT) {
+ max = -1;
+ for (j = lower; j <= upper; j++) {
+ if ((keys = table->subtables[j].keys) > max) {
+ max = keys;
+ pivot = j;
+ }
+ }
+
+ modulo = upper - pivot;
+ if (modulo == 0) {
+ y = pivot;
+ } else{
+ y = pivot + 1 + ((int) Cudd_Random() % modulo);
+ }
+
+ modulo = pivot - lower - 1;
+ if (modulo < 1) {
+ x = lower;
+ } else{
+ do {
+ x = (int) Cudd_Random() % modulo;
+ } while (x == y);
+ }
+ } else {
+ x = ((int) Cudd_Random() % nvars) + lower;
+ do {
+ y = ((int) Cudd_Random() % nvars) + lower;
+ } while (x == y);
+ }
+ previousSize = table->keys - table->isolated;
+ moves = ddSwapAny(table,x,y);
+ if (moves == NULL) goto cuddSwappingOutOfMem;
+ result = ddSiftingBackward(table,previousSize,moves);
+ if (!result) goto cuddSwappingOutOfMem;
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+#ifdef DD_STATS
+ if (table->keys < (unsigned) previousSize + table->isolated) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keys > (unsigned) previousSize + table->isolated) {
+ (void) fprintf(table->out,"+"); /* should never happen */
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+#if 0
+ (void) fprintf(table->out,"#:t_SWAPPING %8d: tmp size\n",
+ table->keys - table->isolated);
+#endif
+ }
+
+ return(1);
+
+cuddSwappingOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+
+ return(0);
+
+} /* end of cuddSwapping */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the next subtable with a larger index.]
+
+ Description [Finds the next subtable with a larger index. Returns the
+ index.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddNextLow]
+
+******************************************************************************/
+int
+cuddNextHigh(
+ DdManager * table,
+ int x)
+{
+ return(x+1);
+
+} /* end of cuddNextHigh */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the next subtable with a smaller index.]
+
+ Description [Finds the next subtable with a smaller index. Returns the
+ index.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddNextHigh]
+
+******************************************************************************/
+int
+cuddNextLow(
+ DdManager * table,
+ int x)
+{
+ return(x-1);
+
+} /* end of cuddNextLow */
+
+
+/**Function********************************************************************
+
+ Synopsis [Swaps two adjacent variables.]
+
+ Description [Swaps two adjacent variables. It assumes that no dead
+ nodes are present on entry to this procedure. The procedure then
+ guarantees that no dead nodes will be present when it terminates.
+ cuddSwapInPlace assumes that x &lt; y. Returns the number of keys in
+ the table if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+int
+cuddSwapInPlace(
+ DdManager * table,
+ int x,
+ int y)
+{
+ DdNodePtr *xlist, *ylist;
+ int xindex, yindex;
+ int xslots, yslots;
+ int xshift, yshift;
+ int oldxkeys, oldykeys;
+ int newxkeys, newykeys;
+ int comple, newcomplement;
+ int i;
+ Cudd_VariableType varType;
+ Cudd_LazyGroupType groupType;
+ int posn;
+ int isolated;
+ DdNode *f,*f0,*f1,*f01,*f00,*f11,*f10,*newf1,*newf0;
+ DdNode *g,*next;
+ DdNodePtr *previousP;
+ DdNode *tmp;
+ DdNode *sentinel = &(table->sentinel);
+ extern void (*MMoutOfMemory)(long);
+ void (*saveHandler)(long);
+
+#if DD_DEBUG
+ int count,idcheck;
+#endif
+
+#ifdef DD_DEBUG
+ assert(x < y);
+ assert(cuddNextHigh(table,x) == y);
+ assert(table->subtables[x].keys != 0);
+ assert(table->subtables[y].keys != 0);
+ assert(table->subtables[x].dead == 0);
+ assert(table->subtables[y].dead == 0);
+#endif
+
+ ddTotalNumberSwapping++;
+
+ /* Get parameters of x subtable. */
+ xindex = table->invperm[x];
+ xlist = table->subtables[x].nodelist;
+ oldxkeys = table->subtables[x].keys;
+ xslots = table->subtables[x].slots;
+ xshift = table->subtables[x].shift;
+
+ /* Get parameters of y subtable. */
+ yindex = table->invperm[y];
+ ylist = table->subtables[y].nodelist;
+ oldykeys = table->subtables[y].keys;
+ yslots = table->subtables[y].slots;
+ yshift = table->subtables[y].shift;
+
+ if (!cuddTestInteract(table,xindex,yindex)) {
+#ifdef DD_STATS
+ ddTotalNISwaps++;
+#endif
+ newxkeys = oldxkeys;
+ newykeys = oldykeys;
+ } else {
+ newxkeys = 0;
+ newykeys = oldykeys;
+
+ /* Check whether the two projection functions involved in this
+ ** swap are isolated. At the end, we'll be able to tell how many
+ ** isolated projection functions are there by checking only these
+ ** two functions again. This is done to eliminate the isolated
+ ** projection functions from the node count.
+ */
+ isolated = - ((table->vars[xindex]->ref == 1) +
+ (table->vars[yindex]->ref == 1));
+
+ /* The nodes in the x layer that do not depend on
+ ** y will stay there; the others are put in a chain.
+ ** The chain is handled as a LIFO; g points to the beginning.
+ */
+ g = NULL;
+ if ((oldxkeys >= xslots || (unsigned) xslots == table->initSlots) &&
+ oldxkeys <= DD_MAX_SUBTABLE_DENSITY * xslots) {
+ for (i = 0; i < xslots; i++) {
+ previousP = &(xlist[i]);
+ f = *previousP;
+ while (f != sentinel) {
+ next = f->next;
+ f1 = cuddT(f); f0 = cuddE(f);
+ if (f1->index != (DdHalfWord) yindex &&
+ Cudd_Regular(f0)->index != (DdHalfWord) yindex) {
+ /* stays */
+ newxkeys++;
+ *previousP = f;
+ previousP = &(f->next);
+ } else {
+ f->index = yindex;
+ f->next = g;
+ g = f;
+ }
+ f = next;
+ } /* while there are elements in the collision chain */
+ *previousP = sentinel;
+ } /* for each slot of the x subtable */
+ } else { /* resize xlist */
+ DdNode *h = NULL;
+ DdNodePtr *newxlist;
+ unsigned int newxslots;
+ int newxshift;
+ /* Empty current xlist. Nodes that stay go to list h;
+ ** nodes that move go to list g. */
+ for (i = 0; i < xslots; i++) {
+ f = xlist[i];
+ while (f != sentinel) {
+ next = f->next;
+ f1 = cuddT(f); f0 = cuddE(f);
+ if (f1->index != (DdHalfWord) yindex &&
+ Cudd_Regular(f0)->index != (DdHalfWord) yindex) {
+ /* stays */
+ f->next = h;
+ h = f;
+ newxkeys++;
+ } else {
+ f->index = yindex;
+ f->next = g;
+ g = f;
+ }
+ f = next;
+ } /* while there are elements in the collision chain */
+ } /* for each slot of the x subtable */
+ /* Decide size of new subtable. */
+ if (oldxkeys > DD_MAX_SUBTABLE_DENSITY * xslots) {
+ newxshift = xshift - 1;
+ newxslots = xslots << 1;
+ } else {
+ newxshift = xshift + 1;
+ newxslots = xslots >> 1;
+ }
+ /* Try to allocate new table. Be ready to back off. */
+ saveHandler = MMoutOfMemory;
+ MMoutOfMemory = Cudd_OutOfMem;
+ newxlist = ALLOC(DdNodePtr, newxslots);
+ MMoutOfMemory = saveHandler;
+ if (newxlist == NULL) {
+ (void) fprintf(table->err, "Unable to resize subtable %d for lack of memory\n", i);
+ newxlist = xlist;
+ newxslots = xslots;
+ newxshift = xshift;
+ } else {
+ table->slots += (newxslots - xslots);
+ table->minDead = (unsigned)
+ (table->gcFrac * (double) table->slots);
+ table->cacheSlack = (int)
+ ddMin(table->maxCacheHard, DD_MAX_CACHE_TO_SLOTS_RATIO
+ * table->slots) - 2 * (int) table->cacheSlots;
+ table->memused += (newxslots - xslots) * sizeof(DdNodePtr);
+ FREE(xlist);
+ xslots = newxslots;
+ xshift = newxshift;
+ xlist = newxlist;
+ }
+ /* Initialize new subtable. */
+ for (i = 0; i < xslots; i++) {
+ xlist[i] = sentinel;
+ }
+ /* Move nodes that were parked in list h to their new home. */
+ f = h;
+ while (f != NULL) {
+ next = f->next;
+ f1 = cuddT(f);
+ f0 = cuddE(f);
+ /* Check xlist for pair (f11,f01). */
+ posn = ddHash(f1, f0, xshift);
+ /* For each element tmp in collision list xlist[posn]. */
+ previousP = &(xlist[posn]);
+ tmp = *previousP;
+ while (f1 < cuddT(tmp)) {
+ previousP = &(tmp->next);
+ tmp = *previousP;
+ }
+ while (f1 == cuddT(tmp) && f0 < cuddE(tmp)) {
+ previousP = &(tmp->next);
+ tmp = *previousP;
+ }
+ f->next = *previousP;
+ *previousP = f;
+ f = next;
+ }
+ }
+
+#ifdef DD_COUNT
+ table->swapSteps += oldxkeys - newxkeys;
+#endif
+ /* Take care of the x nodes that must be re-expressed.
+ ** They form a linked list pointed by g. Their index has been
+ ** already changed to yindex.
+ */
+ f = g;
+ while (f != NULL) {
+ next = f->next;
+ /* Find f1, f0, f11, f10, f01, f00. */
+ f1 = cuddT(f);
+#ifdef DD_DEBUG
+ assert(!(Cudd_IsComplement(f1)));
+#endif
+ if ((int) f1->index == yindex) {
+ f11 = cuddT(f1); f10 = cuddE(f1);
+ } else {
+ f11 = f10 = f1;
+ }
+#ifdef DD_DEBUG
+ assert(!(Cudd_IsComplement(f11)));
+#endif
+ f0 = cuddE(f);
+ comple = Cudd_IsComplement(f0);
+ f0 = Cudd_Regular(f0);
+ if ((int) f0->index == yindex) {
+ f01 = cuddT(f0); f00 = cuddE(f0);
+ } else {
+ f01 = f00 = f0;
+ }
+ if (comple) {
+ f01 = Cudd_Not(f01);
+ f00 = Cudd_Not(f00);
+ }
+ /* Decrease ref count of f1. */
+ cuddSatDec(f1->ref);
+ /* Create the new T child. */
+ if (f11 == f01) {
+ newf1 = f11;
+ cuddSatInc(newf1->ref);
+ } else {
+ /* Check xlist for triple (xindex,f11,f01). */
+ posn = ddHash(f11, f01, xshift);
+ /* For each element newf1 in collision list xlist[posn]. */
+ previousP = &(xlist[posn]);
+ newf1 = *previousP;
+ while (f11 < cuddT(newf1)) {
+ previousP = &(newf1->next);
+ newf1 = *previousP;
+ }
+ while (f11 == cuddT(newf1) && f01 < cuddE(newf1)) {
+ previousP = &(newf1->next);
+ newf1 = *previousP;
+ }
+ if (cuddT(newf1) == f11 && cuddE(newf1) == f01) {
+ cuddSatInc(newf1->ref);
+ } else { /* no match */
+ newf1 = cuddDynamicAllocNode(table);
+ if (newf1 == NULL)
+ goto cuddSwapOutOfMem;
+ newf1->index = xindex; newf1->ref = 1;
+ cuddT(newf1) = f11;
+ cuddE(newf1) = f01;
+ /* Insert newf1 in the collision list xlist[posn];
+ ** increase the ref counts of f11 and f01.
+ */
+ newxkeys++;
+ newf1->next = *previousP;
+ *previousP = newf1;
+ cuddSatInc(f11->ref);
+ tmp = Cudd_Regular(f01);
+ cuddSatInc(tmp->ref);
+ }
+ }
+ cuddT(f) = newf1;
+#ifdef DD_DEBUG
+ assert(!(Cudd_IsComplement(newf1)));
+#endif
+
+ /* Do the same for f0, keeping complement dots into account. */
+ /* Decrease ref count of f0. */
+ tmp = Cudd_Regular(f0);
+ cuddSatDec(tmp->ref);
+ /* Create the new E child. */
+ if (f10 == f00) {
+ newf0 = f00;
+ tmp = Cudd_Regular(newf0);
+ cuddSatInc(tmp->ref);
+ } else {
+ /* make sure f10 is regular */
+ newcomplement = Cudd_IsComplement(f10);
+ if (newcomplement) {
+ f10 = Cudd_Not(f10);
+ f00 = Cudd_Not(f00);
+ }
+ /* Check xlist for triple (xindex,f10,f00). */
+ posn = ddHash(f10, f00, xshift);
+ /* For each element newf0 in collision list xlist[posn]. */
+ previousP = &(xlist[posn]);
+ newf0 = *previousP;
+ while (f10 < cuddT(newf0)) {
+ previousP = &(newf0->next);
+ newf0 = *previousP;
+ }
+ while (f10 == cuddT(newf0) && f00 < cuddE(newf0)) {
+ previousP = &(newf0->next);
+ newf0 = *previousP;
+ }
+ if (cuddT(newf0) == f10 && cuddE(newf0) == f00) {
+ cuddSatInc(newf0->ref);
+ } else { /* no match */
+ newf0 = cuddDynamicAllocNode(table);
+ if (newf0 == NULL)
+ goto cuddSwapOutOfMem;
+ newf0->index = xindex; newf0->ref = 1;
+ cuddT(newf0) = f10;
+ cuddE(newf0) = f00;
+ /* Insert newf0 in the collision list xlist[posn];
+ ** increase the ref counts of f10 and f00.
+ */
+ newxkeys++;
+ newf0->next = *previousP;
+ *previousP = newf0;
+ cuddSatInc(f10->ref);
+ tmp = Cudd_Regular(f00);
+ cuddSatInc(tmp->ref);
+ }
+ if (newcomplement) {
+ newf0 = Cudd_Not(newf0);
+ }
+ }
+ cuddE(f) = newf0;
+
+ /* Insert the modified f in ylist.
+ ** The modified f does not already exists in ylist.
+ ** (Because of the uniqueness of the cofactors.)
+ */
+ posn = ddHash(newf1, newf0, yshift);
+ newykeys++;
+ previousP = &(ylist[posn]);
+ tmp = *previousP;
+ while (newf1 < cuddT(tmp)) {
+ previousP = &(tmp->next);
+ tmp = *previousP;
+ }
+ while (newf1 == cuddT(tmp) && newf0 < cuddE(tmp)) {
+ previousP = &(tmp->next);
+ tmp = *previousP;
+ }
+ f->next = *previousP;
+ *previousP = f;
+ f = next;
+ } /* while f != NULL */
+
+ /* GC the y layer. */
+
+ /* For each node f in ylist. */
+ for (i = 0; i < yslots; i++) {
+ previousP = &(ylist[i]);
+ f = *previousP;
+ while (f != sentinel) {
+ next = f->next;
+ if (f->ref == 0) {
+ tmp = cuddT(f);
+ cuddSatDec(tmp->ref);
+ tmp = Cudd_Regular(cuddE(f));
+ cuddSatDec(tmp->ref);
+ cuddDeallocNode(table,f);
+ newykeys--;
+ } else {
+ *previousP = f;
+ previousP = &(f->next);
+ }
+ f = next;
+ } /* while f */
+ *previousP = sentinel;
+ } /* for i */
+
+#if DD_DEBUG
+#if 0
+ (void) fprintf(table->out,"Swapping %d and %d\n",x,y);
+#endif
+ count = 0;
+ idcheck = 0;
+ for (i = 0; i < yslots; i++) {
+ f = ylist[i];
+ while (f != sentinel) {
+ count++;
+ if (f->index != (DdHalfWord) yindex)
+ idcheck++;
+ f = f->next;
+ }
+ }
+ if (count != newykeys) {
+ (void) fprintf(table->out,
+ "Error in finding newykeys\toldykeys = %d\tnewykeys = %d\tactual = %d\n",
+ oldykeys,newykeys,count);
+ }
+ if (idcheck != 0)
+ (void) fprintf(table->out,
+ "Error in id's of ylist\twrong id's = %d\n",
+ idcheck);
+ count = 0;
+ idcheck = 0;
+ for (i = 0; i < xslots; i++) {
+ f = xlist[i];
+ while (f != sentinel) {
+ count++;
+ if (f->index != (DdHalfWord) xindex)
+ idcheck++;
+ f = f->next;
+ }
+ }
+ if (count != newxkeys) {
+ (void) fprintf(table->out,
+ "Error in finding newxkeys\toldxkeys = %d \tnewxkeys = %d \tactual = %d\n",
+ oldxkeys,newxkeys,count);
+ }
+ if (idcheck != 0)
+ (void) fprintf(table->out,
+ "Error in id's of xlist\twrong id's = %d\n",
+ idcheck);
+#endif
+
+ isolated += (table->vars[xindex]->ref == 1) +
+ (table->vars[yindex]->ref == 1);
+ table->isolated += isolated;
+ }
+
+ /* Set the appropriate fields in table. */
+ table->subtables[x].nodelist = ylist;
+ table->subtables[x].slots = yslots;
+ table->subtables[x].shift = yshift;
+ table->subtables[x].keys = newykeys;
+ table->subtables[x].maxKeys = yslots * DD_MAX_SUBTABLE_DENSITY;
+ i = table->subtables[x].bindVar;
+ table->subtables[x].bindVar = table->subtables[y].bindVar;
+ table->subtables[y].bindVar = i;
+ /* Adjust filds for lazy sifting. */
+ varType = table->subtables[x].varType;
+ table->subtables[x].varType = table->subtables[y].varType;
+ table->subtables[y].varType = varType;
+ i = table->subtables[x].pairIndex;
+ table->subtables[x].pairIndex = table->subtables[y].pairIndex;
+ table->subtables[y].pairIndex = i;
+ i = table->subtables[x].varHandled;
+ table->subtables[x].varHandled = table->subtables[y].varHandled;
+ table->subtables[y].varHandled = i;
+ groupType = table->subtables[x].varToBeGrouped;
+ table->subtables[x].varToBeGrouped = table->subtables[y].varToBeGrouped;
+ table->subtables[y].varToBeGrouped = groupType;
+
+ table->subtables[y].nodelist = xlist;
+ table->subtables[y].slots = xslots;
+ table->subtables[y].shift = xshift;
+ table->subtables[y].keys = newxkeys;
+ table->subtables[y].maxKeys = xslots * DD_MAX_SUBTABLE_DENSITY;
+
+ table->perm[xindex] = y; table->perm[yindex] = x;
+ table->invperm[x] = yindex; table->invperm[y] = xindex;
+
+ table->keys += newxkeys + newykeys - oldxkeys - oldykeys;
+
+ return(table->keys - table->isolated);
+
+cuddSwapOutOfMem:
+ (void) fprintf(table->err,"Error: cuddSwapInPlace out of memory\n");
+
+ return (0);
+
+} /* end of cuddSwapInPlace */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders BDD variables according to the order of the ZDD
+ variables.]
+
+ Description [Reorders BDD variables according to the order of the
+ ZDD variables. This function can be called at the end of ZDD
+ reordering to insure that the order of the BDD variables is
+ consistent with the order of the ZDD variables. The number of ZDD
+ variables must be a multiple of the number of BDD variables. Let
+ <code>M</code> be the ratio of the two numbers. cuddBddAlignToZdd
+ then considers the ZDD variables from <code>M*i</code> to
+ <code>(M+1)*i-1</code> as corresponding to BDD variable
+ <code>i</code>. This function should be normally called from
+ Cudd_zddReduceHeap, which clears the cache. Returns 1 in case of
+ success; 0 otherwise.]
+
+ SideEffects [Changes the BDD variable order for all diagrams and performs
+ garbage collection of the BDD unique table.]
+
+ SeeAlso [Cudd_ShuffleHeap Cudd_zddReduceHeap]
+
+******************************************************************************/
+int
+cuddBddAlignToZdd(
+ DdManager * table /* DD manager */)
+{
+ int *invperm; /* permutation array */
+ int M; /* ratio of ZDD variables to BDD variables */
+ int i; /* loop index */
+ int result; /* return value */
+
+ /* We assume that a ratio of 0 is OK. */
+ if (table->size == 0)
+ return(1);
+
+ M = table->sizeZ / table->size;
+ /* Check whether the number of ZDD variables is a multiple of the
+ ** number of BDD variables.
+ */
+ if (M * table->size != table->sizeZ)
+ return(0);
+ /* Create and initialize the inverse permutation array. */
+ invperm = ALLOC(int,table->size);
+ if (invperm == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (i = 0; i < table->sizeZ; i += M) {
+ int indexZ = table->invpermZ[i];
+ int index = indexZ / M;
+ invperm[i / M] = index;
+ }
+ /* Eliminate dead nodes. Do not scan the cache again, because we
+ ** assume that Cudd_zddReduceHeap has already cleared it.
+ */
+ cuddGarbageCollect(table,0);
+
+ /* Initialize number of isolated projection functions. */
+ table->isolated = 0;
+ for (i = 0; i < table->size; i++) {
+ if (table->vars[i]->ref == 1) table->isolated++;
+ }
+
+ /* Initialize the interaction matrix. */
+ result = cuddInitInteract(table);
+ if (result == 0) return(0);
+
+ result = ddShuffle(table, invperm);
+ FREE(invperm);
+ /* Free interaction matrix. */
+ FREE(table->interact);
+ /* Fix the BDD variable group tree. */
+ bddFixTree(table,table->tree);
+ return(result);
+
+} /* end of cuddBddAlignToZdd */
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Comparison function used by qsort.]
+
+ Description [Comparison function used by qsort to order the
+ variables according to the number of keys in the subtables.
+ Returns the difference in number of keys between the two
+ variables being compared.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddUniqueCompare(
+ int * ptrX,
+ int * ptrY)
+{
+#if 0
+ if (entry[*ptrY] == entry[*ptrX]) {
+ return((*ptrX) - (*ptrY));
+ }
+#endif
+ return(entry[*ptrY] - entry[*ptrX]);
+
+} /* end of ddUniqueCompare */
+
+
+/**Function********************************************************************
+
+ Synopsis [Swaps any two variables.]
+
+ Description [Swaps any two variables. Returns the set of moves.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static Move *
+ddSwapAny(
+ DdManager * table,
+ int x,
+ int y)
+{
+ Move *move, *moves;
+ int xRef,yRef;
+ int xNext,yNext;
+ int size;
+ int limitSize;
+ int tmp;
+
+ if (x >y) {
+ tmp = x; x = y; y = tmp;
+ }
+
+ xRef = x; yRef = y;
+
+ xNext = cuddNextHigh(table,x);
+ yNext = cuddNextLow(table,y);
+ moves = NULL;
+ limitSize = table->keys - table->isolated;
+
+ for (;;) {
+ if ( xNext == yNext) {
+ size = cuddSwapInPlace(table,x,xNext);
+ if (size == 0) goto ddSwapAnyOutOfMem;
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddSwapAnyOutOfMem;
+ move->x = x;
+ move->y = xNext;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+
+ size = cuddSwapInPlace(table,yNext,y);
+ if (size == 0) goto ddSwapAnyOutOfMem;
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddSwapAnyOutOfMem;
+ move->x = yNext;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+
+ size = cuddSwapInPlace(table,x,xNext);
+ if (size == 0) goto ddSwapAnyOutOfMem;
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddSwapAnyOutOfMem;
+ move->x = x;
+ move->y = xNext;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+
+ tmp = x; x = y; y = tmp;
+
+ } else if (x == yNext) {
+
+ size = cuddSwapInPlace(table,x,xNext);
+ if (size == 0) goto ddSwapAnyOutOfMem;
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddSwapAnyOutOfMem;
+ move->x = x;
+ move->y = xNext;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+
+ tmp = x; x = y; y = tmp;
+
+ } else {
+ size = cuddSwapInPlace(table,x,xNext);
+ if (size == 0) goto ddSwapAnyOutOfMem;
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddSwapAnyOutOfMem;
+ move->x = x;
+ move->y = xNext;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+
+ size = cuddSwapInPlace(table,yNext,y);
+ if (size == 0) goto ddSwapAnyOutOfMem;
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddSwapAnyOutOfMem;
+ move->x = yNext;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+
+ x = xNext;
+ y = yNext;
+ }
+
+ xNext = cuddNextHigh(table,x);
+ yNext = cuddNextLow(table,y);
+ if (xNext > yRef) break;
+
+ if ((double) size > table->maxGrowth * (double) limitSize) break;
+ if (size < limitSize) limitSize = size;
+ }
+ if (yNext>=xRef) {
+ size = cuddSwapInPlace(table,yNext,y);
+ if (size == 0) goto ddSwapAnyOutOfMem;
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddSwapAnyOutOfMem;
+ move->x = yNext;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ }
+
+ return(moves);
+
+ddSwapAnyOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+ return(NULL);
+
+} /* end of ddSwapAny */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given xLow <= x <= xHigh moves x up and down between the
+ boundaries.]
+
+ Description [Given xLow <= x <= xHigh moves x up and down between the
+ boundaries. Finds the best position and does the required changes.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddSiftingAux(
+ DdManager * table,
+ int x,
+ int xLow,
+ int xHigh)
+{
+
+ Move *move;
+ Move *moveUp; /* list of up moves */
+ Move *moveDown; /* list of down moves */
+ int initialSize;
+ int result;
+
+ initialSize = table->keys - table->isolated;
+
+ moveDown = NULL;
+ moveUp = NULL;
+
+ if (x == xLow) {
+ moveDown = ddSiftingDown(table,x,xHigh);
+ /* At this point x --> xHigh unless bounding occurred. */
+ if (moveDown == (Move *) CUDD_OUT_OF_MEM) goto ddSiftingAuxOutOfMem;
+ /* Move backward and stop at best position. */
+ result = ddSiftingBackward(table,initialSize,moveDown);
+ if (!result) goto ddSiftingAuxOutOfMem;
+
+ } else if (x == xHigh) {
+ moveUp = ddSiftingUp(table,x,xLow);
+ /* At this point x --> xLow unless bounding occurred. */
+ if (moveUp == (Move *) CUDD_OUT_OF_MEM) goto ddSiftingAuxOutOfMem;
+ /* Move backward and stop at best position. */
+ result = ddSiftingBackward(table,initialSize,moveUp);
+ if (!result) goto ddSiftingAuxOutOfMem;
+
+ } else if ((x - xLow) > (xHigh - x)) { /* must go down first: shorter */
+ moveDown = ddSiftingDown(table,x,xHigh);
+ /* At this point x --> xHigh unless bounding occurred. */
+ if (moveDown == (Move *) CUDD_OUT_OF_MEM) goto ddSiftingAuxOutOfMem;
+ if (moveDown != NULL) {
+ x = moveDown->y;
+ }
+ moveUp = ddSiftingUp(table,x,xLow);
+ if (moveUp == (Move *) CUDD_OUT_OF_MEM) goto ddSiftingAuxOutOfMem;
+ /* Move backward and stop at best position */
+ result = ddSiftingBackward(table,initialSize,moveUp);
+ if (!result) goto ddSiftingAuxOutOfMem;
+
+ } else { /* must go up first: shorter */
+ moveUp = ddSiftingUp(table,x,xLow);
+ /* At this point x --> xLow unless bounding occurred. */
+ if (moveUp == (Move *) CUDD_OUT_OF_MEM) goto ddSiftingAuxOutOfMem;
+ if (moveUp != NULL) {
+ x = moveUp->x;
+ }
+ moveDown = ddSiftingDown(table,x,xHigh);
+ if (moveDown == (Move *) CUDD_OUT_OF_MEM) goto ddSiftingAuxOutOfMem;
+ /* Move backward and stop at best position. */
+ result = ddSiftingBackward(table,initialSize,moveDown);
+ if (!result) goto ddSiftingAuxOutOfMem;
+ }
+
+ while (moveDown != NULL) {
+ move = moveDown->next;
+ cuddDeallocNode(table, (DdNode *) moveDown);
+ moveDown = move;
+ }
+ while (moveUp != NULL) {
+ move = moveUp->next;
+ cuddDeallocNode(table, (DdNode *) moveUp);
+ moveUp = move;
+ }
+
+ return(1);
+
+ddSiftingAuxOutOfMem:
+ if (moveDown != (Move *) CUDD_OUT_OF_MEM) {
+ while (moveDown != NULL) {
+ move = moveDown->next;
+ cuddDeallocNode(table, (DdNode *) moveDown);
+ moveDown = move;
+ }
+ }
+ if (moveUp != (Move *) CUDD_OUT_OF_MEM) {
+ while (moveUp != NULL) {
+ move = moveUp->next;
+ cuddDeallocNode(table, (DdNode *) moveUp);
+ moveUp = move;
+ }
+ }
+
+ return(0);
+
+} /* end of ddSiftingAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts a variable up.]
+
+ Description [Sifts a variable up. Moves y up until either it reaches
+ the bound (xLow) or the size of the DD heap increases too much.
+ Returns the set of moves in case of success; NULL if memory is full.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static Move *
+ddSiftingUp(
+ DdManager * table,
+ int y,
+ int xLow)
+{
+ Move *moves;
+ Move *move;
+ int x;
+ int size;
+ int limitSize;
+ int xindex, yindex;
+ int isolated;
+ int L; /* lower bound on DD size */
+#ifdef DD_DEBUG
+ int checkL;
+ int z;
+ int zindex;
+#endif
+
+ moves = NULL;
+ yindex = table->invperm[y];
+
+ /* Initialize the lower bound.
+ ** The part of the DD below y will not change.
+ ** The part of the DD above y that does not interact with y will not
+ ** change. The rest may vanish in the best case, except for
+ ** the nodes at level xLow, which will not vanish, regardless.
+ */
+ limitSize = L = table->keys - table->isolated;
+ for (x = xLow + 1; x < y; x++) {
+ xindex = table->invperm[x];
+ if (cuddTestInteract(table,xindex,yindex)) {
+ isolated = table->vars[xindex]->ref == 1;
+ L -= table->subtables[x].keys - isolated;
+ }
+ }
+ isolated = table->vars[yindex]->ref == 1;
+ L -= table->subtables[y].keys - isolated;
+
+ x = cuddNextLow(table,y);
+ while (x >= xLow && L <= limitSize) {
+ xindex = table->invperm[x];
+#ifdef DD_DEBUG
+ checkL = table->keys - table->isolated;
+ for (z = xLow + 1; z < y; z++) {
+ zindex = table->invperm[z];
+ if (cuddTestInteract(table,zindex,yindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ checkL -= table->subtables[z].keys - isolated;
+ }
+ }
+ isolated = table->vars[yindex]->ref == 1;
+ checkL -= table->subtables[y].keys - isolated;
+ assert(L == checkL);
+#endif
+ size = cuddSwapInPlace(table,x,y);
+ if (size == 0) goto ddSiftingUpOutOfMem;
+ /* Update the lower bound. */
+ if (cuddTestInteract(table,xindex,yindex)) {
+ isolated = table->vars[xindex]->ref == 1;
+ L += table->subtables[y].keys - isolated;
+ }
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddSiftingUpOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ if ((double) size > (double) limitSize * table->maxGrowth) break;
+ if (size < limitSize) limitSize = size;
+ y = x;
+ x = cuddNextLow(table,y);
+ }
+ return(moves);
+
+ddSiftingUpOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+ return((Move *) CUDD_OUT_OF_MEM);
+
+} /* end of ddSiftingUp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts a variable down.]
+
+ Description [Sifts a variable down. Moves x down until either it
+ reaches the bound (xHigh) or the size of the DD heap increases too
+ much. Returns the set of moves in case of success; NULL if memory is
+ full.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static Move *
+ddSiftingDown(
+ DdManager * table,
+ int x,
+ int xHigh)
+{
+ Move *moves;
+ Move *move;
+ int y;
+ int size;
+ int R; /* upper bound on node decrease */
+ int limitSize;
+ int xindex, yindex;
+ int isolated;
+#ifdef DD_DEBUG
+ int checkR;
+ int z;
+ int zindex;
+#endif
+
+ moves = NULL;
+ /* Initialize R */
+ xindex = table->invperm[x];
+ limitSize = size = table->keys - table->isolated;
+ R = 0;
+ for (y = xHigh; y > x; y--) {
+ yindex = table->invperm[y];
+ if (cuddTestInteract(table,xindex,yindex)) {
+ isolated = table->vars[yindex]->ref == 1;
+ R += table->subtables[y].keys - isolated;
+ }
+ }
+
+ y = cuddNextHigh(table,x);
+ while (y <= xHigh && size - R < limitSize) {
+#ifdef DD_DEBUG
+ checkR = 0;
+ for (z = xHigh; z > x; z--) {
+ zindex = table->invperm[z];
+ if (cuddTestInteract(table,xindex,zindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ checkR += table->subtables[z].keys - isolated;
+ }
+ }
+ assert(R == checkR);
+#endif
+ /* Update upper bound on node decrease. */
+ yindex = table->invperm[y];
+ if (cuddTestInteract(table,xindex,yindex)) {
+ isolated = table->vars[yindex]->ref == 1;
+ R -= table->subtables[y].keys - isolated;
+ }
+ size = cuddSwapInPlace(table,x,y);
+ if (size == 0) goto ddSiftingDownOutOfMem;
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddSiftingDownOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ if ((double) size > (double) limitSize * table->maxGrowth) break;
+ if (size < limitSize) limitSize = size;
+ x = y;
+ y = cuddNextHigh(table,x);
+ }
+ return(moves);
+
+ddSiftingDownOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+ return((Move *) CUDD_OUT_OF_MEM);
+
+} /* end of ddSiftingDown */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given a set of moves, returns the DD heap to the position
+ giving the minimum size.]
+
+ Description [Given a set of moves, returns the DD heap to the
+ position giving the minimum size. In case of ties, returns to the
+ closest position giving the minimum size. Returns 1 in case of
+ success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddSiftingBackward(
+ DdManager * table,
+ int size,
+ Move * moves)
+{
+ Move *move;
+ int res;
+
+ for (move = moves; move != NULL; move = move->next) {
+ if (move->size < size) {
+ size = move->size;
+ }
+ }
+
+ for (move = moves; move != NULL; move = move->next) {
+ if (move->size == size) return(1);
+ res = cuddSwapInPlace(table,(int)move->x,(int)move->y);
+ if (!res) return(0);
+ }
+
+ return(1);
+
+} /* end of ddSiftingBackward */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prepares the DD heap for dynamic reordering.]
+
+ Description [Prepares the DD heap for dynamic reordering. Does
+ garbage collection, to guarantee that there are no dead nodes;
+ clears the cache, which is invalidated by dynamic reordering; initializes
+ the number of isolated projection functions; and initializes the
+ interaction matrix. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddReorderPreprocess(
+ DdManager * table)
+{
+ int i;
+ int res;
+
+ /* Clear the cache. */
+ cuddCacheFlush(table);
+ cuddLocalCacheClearAll(table);
+
+ /* Eliminate dead nodes. Do not scan the cache again. */
+ cuddGarbageCollect(table,0);
+
+ /* Initialize number of isolated projection functions. */
+ table->isolated = 0;
+ for (i = 0; i < table->size; i++) {
+ if (table->vars[i]->ref == 1) table->isolated++;
+ }
+
+ /* Initialize the interaction matrix. */
+ res = cuddInitInteract(table);
+ if (res == 0) return(0);
+
+ return(1);
+
+} /* end of ddReorderPreprocess */
+
+
+/**Function********************************************************************
+
+ Synopsis [Cleans up at the end of reordering.]
+
+ Description []
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddReorderPostprocess(
+ DdManager * table)
+{
+
+#ifdef DD_VERBOSE
+ (void) fflush(table->out);
+#endif
+
+ /* Free interaction matrix. */
+ FREE(table->interact);
+
+ return(1);
+
+} /* end of ddReorderPostprocess */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders variables according to a given permutation.]
+
+ Description [Reorders variables according to a given permutation.
+ The i-th permutation array contains the index of the variable that
+ should be brought to the i-th level. ddShuffle assumes that no
+ dead nodes are present and that the interaction matrix is properly
+ initialized. The reordering is achieved by a series of upward sifts.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+ddShuffle(
+ DdManager * table,
+ int * permutation)
+{
+ int index;
+ int level;
+ int position;
+ int numvars;
+ int result;
+#ifdef DD_STATS
+ long localTime;
+ int initialSize;
+ int finalSize;
+ int previousSize;
+#endif
+
+ ddTotalNumberSwapping = 0;
+#ifdef DD_STATS
+ localTime = util_cpu_time();
+ initialSize = table->keys - table->isolated;
+ (void) fprintf(table->out,"#:I_SHUFFLE %8d: initial size\n",
+ initialSize);
+ ddTotalNISwaps = 0;
+#endif
+
+ numvars = table->size;
+
+ for (level = 0; level < numvars; level++) {
+ index = permutation[level];
+ position = table->perm[index];
+#ifdef DD_STATS
+ previousSize = table->keys - table->isolated;
+#endif
+ result = ddSiftUp(table,position,level);
+ if (!result) return(0);
+#ifdef DD_STATS
+ if (table->keys < (unsigned) previousSize + table->isolated) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keys > (unsigned) previousSize + table->isolated) {
+ (void) fprintf(table->out,"+"); /* should never happen */
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\n");
+ finalSize = table->keys - table->isolated;
+ (void) fprintf(table->out,"#:F_SHUFFLE %8d: final size\n",finalSize);
+ (void) fprintf(table->out,"#:T_SHUFFLE %8g: total time (sec)\n",
+ ((double)(util_cpu_time() - localTime)/1000.0));
+ (void) fprintf(table->out,"#:N_SHUFFLE %8d: total swaps\n",
+ ddTotalNumberSwapping);
+ (void) fprintf(table->out,"#:M_SHUFFLE %8d: NI swaps\n",ddTotalNISwaps);
+#endif
+
+ return(1);
+
+} /* end of ddShuffle */
+
+
+/**Function********************************************************************
+
+ Synopsis [Moves one variable up.]
+
+ Description [Takes a variable from position x and sifts it up to
+ position xLow; xLow should be less than or equal to x.
+ Returns 1 if successful; 0 otherwise]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+ddSiftUp(
+ DdManager * table,
+ int x,
+ int xLow)
+{
+ int y;
+ int size;
+
+ y = cuddNextLow(table,x);
+ while (y >= xLow) {
+ size = cuddSwapInPlace(table,y,x);
+ if (size == 0) {
+ return(0);
+ }
+ x = y;
+ y = cuddNextLow(table,x);
+ }
+ return(1);
+
+} /* end of ddSiftUp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Fixes the BDD variable group tree after a shuffle.]
+
+ Description [Fixes the BDD variable group tree after a
+ shuffle. Assumes that the order of the variables in a terminal node
+ has not been changed.]
+
+ SideEffects [Changes the BDD variable group tree.]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+bddFixTree(
+ DdManager * table,
+ MtrNode * treenode)
+{
+ if (treenode == NULL) return;
+ treenode->low = ((int) treenode->index < table->size) ?
+ table->perm[treenode->index] : treenode->index;
+ if (treenode->child != NULL) {
+ bddFixTree(table, treenode->child);
+ }
+ if (treenode->younger != NULL)
+ bddFixTree(table, treenode->younger);
+ if (treenode->parent != NULL && treenode->low < treenode->parent->low) {
+ treenode->parent->low = treenode->low;
+ treenode->parent->index = treenode->index;
+ }
+ return;
+
+} /* end of bddFixTree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Updates the BDD variable group tree before a shuffle.]
+
+ Description [Updates the BDD variable group tree before a shuffle.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [Changes the BDD variable group tree.]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+ddUpdateMtrTree(
+ DdManager * table,
+ MtrNode * treenode,
+ int * perm,
+ int * invperm)
+{
+ int i, size, index, level;
+ int minLevel, maxLevel, minIndex;
+
+ if (treenode == NULL) return(1);
+
+ /* i : level */
+ for (i = treenode->low; i < treenode->low + treenode->size; i++) {
+ index = table->invperm[i];
+ level = perm[index];
+ if (level < minLevel) {
+ minLevel = level;
+ minIndex = index;
+ }
+ if (level > maxLevel)
+ maxLevel = level;
+ }
+ size = maxLevel - minLevel + 1;
+ if (size == treenode->size) {
+ treenode->low = minLevel;
+ treenode->index = minIndex;
+ } else
+ return(0);
+
+ if (treenode->child != NULL) {
+ if (!ddUpdateMtrTree(table, treenode->child, perm, invperm))
+ return(0);
+ }
+ if (treenode->younger != NULL) {
+ if (!ddUpdateMtrTree(table, treenode->younger, perm, invperm))
+ return(0);
+ }
+ return(1);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks the BDD variable group tree before a shuffle.]
+
+ Description [Checks the BDD variable group tree before a shuffle.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [Changes the BDD variable group tree.]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+ddCheckPermuation(
+ DdManager * table,
+ MtrNode * treenode,
+ int * perm,
+ int * invperm)
+{
+ int i, size, index, level;
+ int minLevel, maxLevel;
+
+ if (treenode == NULL) return(1);
+
+ minLevel = table->size;
+ maxLevel = 0;
+ /* i : level */
+ for (i = treenode->low; i < treenode->low + treenode->size; i++) {
+ index = table->invperm[i];
+ level = perm[index];
+ if (level < minLevel)
+ minLevel = level;
+ if (level > maxLevel)
+ maxLevel = level;
+ }
+ size = maxLevel - minLevel + 1;
+ if (size != treenode->size)
+ return(0);
+
+ if (treenode->child != NULL) {
+ if (!ddCheckPermuation(table, treenode->child, perm, invperm))
+ return(0);
+ }
+ if (treenode->younger != NULL) {
+ if (!ddCheckPermuation(table, treenode->younger, perm, invperm))
+ return(0);
+ }
+ return(1);
+}
diff --git a/src/bdd/cudd/cuddSat.c b/src/bdd/cudd/cuddSat.c
new file mode 100644
index 00000000..dde33a5b
--- /dev/null
+++ b/src/bdd/cudd/cuddSat.c
@@ -0,0 +1,1305 @@
+/**CFile***********************************************************************
+
+ FileName [cuddSat.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions for the solution of satisfiability related
+ problems.]
+
+ Description [External procedures included in this file:
+ <ul>
+ <li> Cudd_Eval()
+ <li> Cudd_ShortestPath()
+ <li> Cudd_LargestCube()
+ <li> Cudd_ShortestLength()
+ <li> Cudd_Decreasing()
+ <li> Cudd_Increasing()
+ <li> Cudd_EquivDC()
+ <li> Cudd_bddLeqUnless()
+ <li> Cudd_EqualSupNorm()
+ <li> Cudd_bddMakePrime()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddBddMakePrime()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> freePathPair()
+ <li> getShortest()
+ <li> getPath()
+ <li> getLargest()
+ <li> getCube()
+ </ul>]
+
+ Author [Seh-Woong Jeong, Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define DD_BIGGY 1000000
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+typedef struct cuddPathPair {
+ int pos;
+ int neg;
+} cuddPathPair;
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddSat.c,v 1.1.1.1 2003/02/24 22:23:53 wjiang Exp $";
+#endif
+
+static DdNode *one, *zero;
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+#define WEIGHT(weight, col) ((weight) == NULL ? 1 : weight[col])
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static enum st_retval freePathPair ARGS((char *key, char *value, char *arg));
+static cuddPathPair getShortest ARGS((DdNode *root, int *cost, int *support, st_table *visited));
+static DdNode * getPath ARGS((DdManager *manager, st_table *visited, DdNode *f, int *weight, int cost));
+static cuddPathPair getLargest ARGS((DdNode *root, st_table *visited));
+static DdNode * getCube ARGS((DdManager *manager, st_table *visited, DdNode *f, int cost));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the value of a DD for a given variable assignment.]
+
+ Description [Finds the value of a DD for a given variable
+ assignment. The variable assignment is passed in an array of int's,
+ that should specify a zero or a one for each variable in the support
+ of the function. Returns a pointer to a constant node. No new nodes
+ are produced.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddLeq Cudd_addEvalConst]
+
+******************************************************************************/
+DdNode *
+Cudd_Eval(
+ DdManager * dd,
+ DdNode * f,
+ int * inputs)
+{
+ int comple;
+ DdNode *ptr;
+
+ comple = Cudd_IsComplement(f);
+ ptr = Cudd_Regular(f);
+
+ while (!cuddIsConstant(ptr)) {
+ if (inputs[ptr->index] == 1) {
+ ptr = cuddT(ptr);
+ } else {
+ comple ^= Cudd_IsComplement(cuddE(ptr));
+ ptr = Cudd_Regular(cuddE(ptr));
+ }
+ }
+ return(Cudd_NotCond(ptr,comple));
+
+} /* end of Cudd_Eval */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds a shortest path in a DD.]
+
+ Description [Finds a shortest path in a DD. f is the DD we want to
+ get the shortest path for; weight\[i\] is the weight of the THEN arc
+ coming from the node whose index is i. If weight is NULL, then unit
+ weights are assumed for all THEN arcs. All ELSE arcs have 0 weight.
+ If non-NULL, both weight and support should point to arrays with at
+ least as many entries as there are variables in the manager.
+ Returns the shortest path as the BDD of a cube.]
+
+ SideEffects [support contains on return the true support of f.
+ If support is NULL on entry, then Cudd_ShortestPath does not compute
+ the true support info. length contains the length of the path.]
+
+ SeeAlso [Cudd_ShortestLength Cudd_LargestCube]
+
+******************************************************************************/
+DdNode *
+Cudd_ShortestPath(
+ DdManager * manager,
+ DdNode * f,
+ int * weight,
+ int * support,
+ int * length)
+{
+ register DdNode *F;
+ st_table *visited;
+ DdNode *sol;
+ cuddPathPair *rootPair;
+ int complement, cost;
+ int i;
+
+ one = DD_ONE(manager);
+ zero = DD_ZERO(manager);
+
+ /* Initialize support. */
+ if (support) {
+ for (i = 0; i < manager->size; i++) {
+ support[i] = 0;
+ }
+ }
+
+ if (f == Cudd_Not(one) || f == zero) {
+ *length = DD_BIGGY;
+ return(Cudd_Not(one));
+ }
+ /* From this point on, a path exists. */
+
+ /* Initialize visited table. */
+ visited = st_init_table(st_ptrcmp, st_ptrhash);
+
+ /* Now get the length of the shortest path(s) from f to 1. */
+ (void) getShortest(f, weight, support, visited);
+
+ complement = Cudd_IsComplement(f);
+
+ F = Cudd_Regular(f);
+
+ st_lookup(visited, (char *)F, (char **)&rootPair);
+
+ if (complement) {
+ cost = rootPair->neg;
+ } else {
+ cost = rootPair->pos;
+ }
+
+ /* Recover an actual shortest path. */
+ do {
+ manager->reordered = 0;
+ sol = getPath(manager,visited,f,weight,cost);
+ } while (manager->reordered == 1);
+
+ st_foreach(visited, freePathPair, NULL);
+ st_free_table(visited);
+
+ *length = cost;
+ return(sol);
+
+} /* end of Cudd_ShortestPath */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds a largest cube in a DD.]
+
+ Description [Finds a largest cube in a DD. f is the DD we want to
+ get the largest cube for. The problem is translated into the one of
+ finding a shortest path in f, when both THEN and ELSE arcs are assumed to
+ have unit length. This yields a largest cube in the disjoint cover
+ corresponding to the DD. Therefore, it is not necessarily the largest
+ implicant of f. Returns the largest cube as a BDD.]
+
+ SideEffects [The number of literals of the cube is returned in length.]
+
+ SeeAlso [Cudd_ShortestPath]
+
+******************************************************************************/
+DdNode *
+Cudd_LargestCube(
+ DdManager * manager,
+ DdNode * f,
+ int * length)
+{
+ register DdNode *F;
+ st_table *visited;
+ DdNode *sol;
+ cuddPathPair *rootPair;
+ int complement, cost;
+
+ one = DD_ONE(manager);
+ zero = DD_ZERO(manager);
+
+ if (f == Cudd_Not(one) || f == zero) {
+ *length = DD_BIGGY;
+ return(Cudd_Not(one));
+ }
+ /* From this point on, a path exists. */
+
+ /* Initialize visited table. */
+ visited = st_init_table(st_ptrcmp, st_ptrhash);
+
+ /* Now get the length of the shortest path(s) from f to 1. */
+ (void) getLargest(f, visited);
+
+ complement = Cudd_IsComplement(f);
+
+ F = Cudd_Regular(f);
+
+ st_lookup(visited, (char *)F, (char **)&rootPair);
+
+ if (complement) {
+ cost = rootPair->neg;
+ } else {
+ cost = rootPair->pos;
+ }
+
+ /* Recover an actual shortest path. */
+ do {
+ manager->reordered = 0;
+ sol = getCube(manager,visited,f,cost);
+ } while (manager->reordered == 1);
+
+ st_foreach(visited, freePathPair, NULL);
+ st_free_table(visited);
+
+ *length = cost;
+ return(sol);
+
+} /* end of Cudd_LargestCube */
+
+
+/**Function********************************************************************
+
+ Synopsis [Find the length of the shortest path(s) in a DD.]
+
+ Description [Find the length of the shortest path(s) in a DD. f is
+ the DD we want to get the shortest path for; weight\[i\] is the
+ weight of the THEN edge coming from the node whose index is i. All
+ ELSE edges have 0 weight. Returns the length of the shortest
+ path(s) if successful; CUDD_OUT_OF_MEM otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ShortestPath]
+
+******************************************************************************/
+int
+Cudd_ShortestLength(
+ DdManager * manager,
+ DdNode * f,
+ int * weight)
+{
+ register DdNode *F;
+ st_table *visited;
+ cuddPathPair *my_pair;
+ int complement, cost;
+
+ one = DD_ONE(manager);
+ zero = DD_ZERO(manager);
+
+ if (f == Cudd_Not(one) || f == zero) {
+ return(DD_BIGGY);
+ }
+
+ /* From this point on, a path exists. */
+ /* Initialize visited table and support. */
+ visited = st_init_table(st_ptrcmp, st_ptrhash);
+
+ /* Now get the length of the shortest path(s) from f to 1. */
+ (void) getShortest(f, weight, NULL, visited);
+
+ complement = Cudd_IsComplement(f);
+
+ F = Cudd_Regular(f);
+
+ st_lookup(visited, (char *)F, (char **)&my_pair);
+
+ if (complement) {
+ cost = my_pair->neg;
+ } else {
+ cost = my_pair->pos;
+ }
+
+ st_foreach(visited, freePathPair, NULL);
+ st_free_table(visited);
+
+ return(cost);
+
+} /* end of Cudd_ShortestLength */
+
+
+/**Function********************************************************************
+
+ Synopsis [Determines whether a BDD is negative unate in a
+ variable.]
+
+ Description [Determines whether the function represented by BDD f is
+ negative unate (monotonic decreasing) in variable i. Returns the
+ constant one is f is unate and the (logical) constant zero if it is not.
+ This function does not generate any new nodes.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Increasing]
+
+******************************************************************************/
+DdNode *
+Cudd_Decreasing(
+ DdManager * dd,
+ DdNode * f,
+ int i)
+{
+ unsigned int topf, level;
+ DdNode *F, *fv, *fvn, *res;
+ DdNode *(*cacheOp)(DdManager *, DdNode *, DdNode *);
+
+ statLine(dd);
+#ifdef DD_DEBUG
+ assert(0 <= i && i < dd->size);
+#endif
+
+ F = Cudd_Regular(f);
+ topf = cuddI(dd,F->index);
+
+ /* Check terminal case. If topf > i, f does not depend on var.
+ ** Therefore, f is unate in i.
+ */
+ level = (unsigned) dd->perm[i];
+ if (topf > level) {
+ return(DD_ONE(dd));
+ }
+
+ /* From now on, f is not constant. */
+
+ /* Check cache. */
+ cacheOp = (DdNode *(*)(DdManager *, DdNode *, DdNode *)) Cudd_Decreasing;
+ res = cuddCacheLookup2(dd,cacheOp,f,dd->vars[i]);
+ if (res != NULL) {
+ return(res);
+ }
+
+ /* Compute cofactors. */
+ fv = cuddT(F); fvn = cuddE(F);
+ if (F != f) {
+ fv = Cudd_Not(fv);
+ fvn = Cudd_Not(fvn);
+ }
+
+ if (topf == (unsigned) level) {
+ /* Special case: if fv is regular, fv(1,...,1) = 1;
+ ** If in addition fvn is complemented, fvn(1,...,1) = 0.
+ ** But then f(1,1,...,1) > f(0,1,...,1). Hence f is not
+ ** monotonic decreasing in i.
+ */
+ if (!Cudd_IsComplement(fv) && Cudd_IsComplement(fvn)) {
+ return(Cudd_Not(DD_ONE(dd)));
+ }
+ res = Cudd_bddLeq(dd,fv,fvn) ? DD_ONE(dd) : Cudd_Not(DD_ONE(dd));
+ } else {
+ res = Cudd_Decreasing(dd,fv,i);
+ if (res == DD_ONE(dd)) {
+ res = Cudd_Decreasing(dd,fvn,i);
+ }
+ }
+
+ cuddCacheInsert2(dd,cacheOp,f,dd->vars[i],res);
+ return(res);
+
+} /* end of Cudd_Decreasing */
+
+
+/**Function********************************************************************
+
+ Synopsis [Determines whether a BDD is positive unate in a
+ variable.]
+
+ Description [Determines whether the function represented by BDD f is
+ positive unate (monotonic decreasing) in variable i. It is based on
+ Cudd_Decreasing and the fact that f is monotonic increasing in i if
+ and only if its complement is monotonic decreasing in i.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Decreasing]
+
+******************************************************************************/
+DdNode *
+Cudd_Increasing(
+ DdManager * dd,
+ DdNode * f,
+ int i)
+{
+ return(Cudd_Decreasing(dd,Cudd_Not(f),i));
+
+} /* end of Cudd_Increasing */
+
+
+/**Function********************************************************************
+
+ Synopsis [Tells whether F and G are identical wherever D is 0.]
+
+ Description [Tells whether F and G are identical wherever D is 0. F
+ and G are either two ADDs or two BDDs. D is either a 0-1 ADD or a
+ BDD. The function returns 1 if F and G are equivalent, and 0
+ otherwise. No new nodes are created.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddLeqUnless]
+
+******************************************************************************/
+int
+Cudd_EquivDC(
+ DdManager * dd,
+ DdNode * F,
+ DdNode * G,
+ DdNode * D)
+{
+ DdNode *tmp, *One, *Gr, *Dr;
+ DdNode *Fv, *Fvn, *Gv, *Gvn, *Dv, *Dvn;
+ int res;
+ unsigned int flevel, glevel, dlevel, top;
+
+ One = DD_ONE(dd);
+
+ statLine(dd);
+ /* Check terminal cases. */
+ if (D == One || F == G) return(1);
+ if (D == Cudd_Not(One) || D == DD_ZERO(dd) || F == Cudd_Not(G)) return(0);
+
+ /* From now on, D is non-constant. */
+
+ /* Normalize call to increase cache efficiency. */
+ if (F > G) {
+ tmp = F;
+ F = G;
+ G = tmp;
+ }
+ if (Cudd_IsComplement(F)) {
+ F = Cudd_Not(F);
+ G = Cudd_Not(G);
+ }
+
+ /* From now on, F is regular. */
+
+ /* Check cache. */
+ tmp = cuddCacheLookup(dd,DD_EQUIV_DC_TAG,F,G,D);
+ if (tmp != NULL) return(tmp == One);
+
+ /* Find splitting variable. */
+ flevel = cuddI(dd,F->index);
+ Gr = Cudd_Regular(G);
+ glevel = cuddI(dd,Gr->index);
+ top = ddMin(flevel,glevel);
+ Dr = Cudd_Regular(D);
+ dlevel = dd->perm[Dr->index];
+ top = ddMin(top,dlevel);
+
+ /* Compute cofactors. */
+ if (top == flevel) {
+ Fv = cuddT(F);
+ Fvn = cuddE(F);
+ } else {
+ Fv = Fvn = F;
+ }
+ if (top == glevel) {
+ Gv = cuddT(Gr);
+ Gvn = cuddE(Gr);
+ if (G != Gr) {
+ Gv = Cudd_Not(Gv);
+ Gvn = Cudd_Not(Gvn);
+ }
+ } else {
+ Gv = Gvn = G;
+ }
+ if (top == dlevel) {
+ Dv = cuddT(Dr);
+ Dvn = cuddE(Dr);
+ if (D != Dr) {
+ Dv = Cudd_Not(Dv);
+ Dvn = Cudd_Not(Dvn);
+ }
+ } else {
+ Dv = Dvn = D;
+ }
+
+ /* Solve recursively. */
+ res = Cudd_EquivDC(dd,Fv,Gv,Dv);
+ if (res != 0) {
+ res = Cudd_EquivDC(dd,Fvn,Gvn,Dvn);
+ }
+ cuddCacheInsert(dd,DD_EQUIV_DC_TAG,F,G,D,(res) ? One : Cudd_Not(One));
+
+ return(res);
+
+} /* end of Cudd_EquivDC */
+
+
+/**Function********************************************************************
+
+ Synopsis [Tells whether f is less than of equal to G unless D is 1.]
+
+ Description [Tells whether f is less than of equal to G unless D is
+ 1. f, g, and D are BDDs. The function returns 1 if f is less than
+ of equal to G, and 0 otherwise. No new nodes are created.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_EquivDC Cudd_bddLeq Cudd_bddIteConstant]
+
+******************************************************************************/
+int
+Cudd_bddLeqUnless(
+ DdManager *dd,
+ DdNode *f,
+ DdNode *g,
+ DdNode *D)
+{
+ DdNode *tmp, *One, *F, *G;
+ DdNode *Ft, *Fe, *Gt, *Ge, *Dt, *De;
+ int res;
+ unsigned int flevel, glevel, dlevel, top;
+
+ statLine(dd);
+
+ One = DD_ONE(dd);
+
+ /* Check terminal cases. */
+ if (f == g || g == One || f == Cudd_Not(One) || D == One ||
+ D == f || D == Cudd_Not(g)) return(1);
+ /* Check for two-operand cases. */
+ if (D == Cudd_Not(One) || D == g || D == Cudd_Not(f))
+ return(Cudd_bddLeq(dd,f,g));
+ if (g == Cudd_Not(One) || g == Cudd_Not(f)) return(Cudd_bddLeq(dd,f,D));
+ if (f == One) return(Cudd_bddLeq(dd,Cudd_Not(g),D));
+
+ /* From now on, f, g, and D are non-constant, distinct, and
+ ** non-complementary. */
+
+ /* Normalize call to increase cache efficiency. We rely on the
+ ** fact that f <= g unless D is equivalent to not(g) <= not(f)
+ ** unless D and to f <= D unless g. We make sure that D is
+ ** regular, and that at most one of f and g is complemented. We also
+ ** ensure that when two operands can be swapped, the one with the
+ ** lowest address comes first. */
+
+ if (Cudd_IsComplement(D)) {
+ if (Cudd_IsComplement(g)) {
+ /* Special case: if f is regular and g is complemented,
+ ** f(1,...,1) = 1 > 0 = g(1,...,1). If D(1,...,1) = 0, return 0.
+ */
+ if (!Cudd_IsComplement(f)) return(0);
+ /* !g <= D unless !f or !D <= g unless !f */
+ tmp = D;
+ D = Cudd_Not(f);
+ if (g < tmp) {
+ f = Cudd_Not(g);
+ g = tmp;
+ } else {
+ f = Cudd_Not(tmp);
+ }
+ } else {
+ if (Cudd_IsComplement(f)) {
+ /* !D <= !f unless g or !D <= g unless !f */
+ tmp = f;
+ f = Cudd_Not(D);
+ if (tmp < g) {
+ D = g;
+ g = Cudd_Not(tmp);
+ } else {
+ D = Cudd_Not(tmp);
+ }
+ } else {
+ /* f <= D unless g or !D <= !f unless g */
+ tmp = D;
+ D = g;
+ if (tmp < f) {
+ g = Cudd_Not(f);
+ f = Cudd_Not(tmp);
+ } else {
+ g = tmp;
+ }
+ }
+ }
+ } else {
+ if (Cudd_IsComplement(g)) {
+ if (Cudd_IsComplement(f)) {
+ /* !g <= !f unless D or !g <= D unless !f */
+ tmp = f;
+ f = Cudd_Not(g);
+ if (D < tmp) {
+ g = D;
+ D = Cudd_Not(tmp);
+ } else {
+ g = Cudd_Not(tmp);
+ }
+ } else {
+ /* f <= g unless D or !g <= !f unless D */
+ if (g < f) {
+ tmp = g;
+ g = Cudd_Not(f);
+ f = Cudd_Not(tmp);
+ }
+ }
+ } else {
+ /* f <= g unless D or f <= D unless g */
+ if (D < g) {
+ tmp = D;
+ D = g;
+ g = tmp;
+ }
+ }
+ }
+
+ /* From now on, D is regular. */
+
+ /* Check cache. */
+ tmp = cuddCacheLookup(dd,DD_BDD_LEQ_UNLESS_TAG,f,g,D);
+ if (tmp != NULL) return(tmp == One);
+
+ /* Find splitting variable. */
+ F = Cudd_Regular(f);
+ flevel = dd->perm[F->index];
+ G = Cudd_Regular(g);
+ glevel = dd->perm[G->index];
+ top = ddMin(flevel,glevel);
+ dlevel = dd->perm[D->index];
+ top = ddMin(top,dlevel);
+
+ /* Compute cofactors. */
+ if (top == flevel) {
+ Ft = cuddT(F);
+ Fe = cuddE(F);
+ if (F != f) {
+ Ft = Cudd_Not(Ft);
+ Fe = Cudd_Not(Fe);
+ }
+ } else {
+ Ft = Fe = f;
+ }
+ if (top == glevel) {
+ Gt = cuddT(G);
+ Ge = cuddE(G);
+ if (G != g) {
+ Gt = Cudd_Not(Gt);
+ Ge = Cudd_Not(Ge);
+ }
+ } else {
+ Gt = Ge = g;
+ }
+ if (top == dlevel) {
+ Dt = cuddT(D);
+ De = cuddE(D);
+ } else {
+ Dt = De = D;
+ }
+
+ /* Solve recursively. */
+ res = Cudd_bddLeqUnless(dd,Ft,Gt,Dt);
+ if (res != 0) {
+ res = Cudd_bddLeqUnless(dd,Fe,Ge,De);
+ }
+ cuddCacheInsert(dd,DD_BDD_LEQ_UNLESS_TAG,f,g,D,Cudd_NotCond(One,!res));
+
+ return(res);
+
+} /* end of Cudd_bddLeqUnless */
+
+
+/**Function********************************************************************
+
+ Synopsis [Compares two ADDs for equality within tolerance.]
+
+ Description [Compares two ADDs for equality within tolerance. Two
+ ADDs are reported to be equal if the maximum difference between them
+ (the sup norm of their difference) is less than or equal to the
+ tolerance parameter. Returns 1 if the two ADDs are equal (within
+ tolerance); 0 otherwise. If parameter <code>pr</code> is positive
+ the first failure is reported to the standard output.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+Cudd_EqualSupNorm(
+ DdManager * dd /* manager */,
+ DdNode * f /* first ADD */,
+ DdNode * g /* second ADD */,
+ CUDD_VALUE_TYPE tolerance /* maximum allowed difference */,
+ int pr /* verbosity level */)
+{
+ DdNode *fv, *fvn, *gv, *gvn, *r;
+ unsigned int topf, topg;
+
+ statLine(dd);
+ /* Check terminal cases. */
+ if (f == g) return(1);
+ if (Cudd_IsConstant(f) && Cudd_IsConstant(g)) {
+ if (ddEqualVal(cuddV(f),cuddV(g),tolerance)) {
+ return(1);
+ } else {
+ if (pr>0) {
+ (void) fprintf(dd->out,"Offending nodes:\n");
+#if SIZEOF_VOID_P == 8
+ (void) fprintf(dd->out,
+ "f: address = %lx\t value = %40.30f\n",
+ (unsigned long) f, cuddV(f));
+ (void) fprintf(dd->out,
+ "g: address = %lx\t value = %40.30f\n",
+ (unsigned long) g, cuddV(g));
+#else
+ (void) fprintf(dd->out,
+ "f: address = %x\t value = %40.30f\n",
+ (unsigned) f, cuddV(f));
+ (void) fprintf(dd->out,
+ "g: address = %x\t value = %40.30f\n",
+ (unsigned) g, cuddV(g));
+#endif
+ }
+ return(0);
+ }
+ }
+
+ /* We only insert the result in the cache if the comparison is
+ ** successful. Therefore, if we hit we return 1. */
+ r = cuddCacheLookup2(dd,(DdNode * (*)(DdManager *, DdNode *, DdNode *))Cudd_EqualSupNorm,f,g);
+ if (r != NULL) {
+ return(1);
+ }
+
+ /* Compute the cofactors and solve the recursive subproblems. */
+ topf = cuddI(dd,f->index);
+ topg = cuddI(dd,g->index);
+
+ if (topf <= topg) {fv = cuddT(f); fvn = cuddE(f);} else {fv = fvn = f;}
+ if (topg <= topf) {gv = cuddT(g); gvn = cuddE(g);} else {gv = gvn = g;}
+
+ if (!Cudd_EqualSupNorm(dd,fv,gv,tolerance,pr)) return(0);
+ if (!Cudd_EqualSupNorm(dd,fvn,gvn,tolerance,pr)) return(0);
+
+ cuddCacheInsert2(dd,(DdNode * (*)(DdManager *, DdNode *, DdNode *))Cudd_EqualSupNorm,f,g,DD_ONE(dd));
+
+ return(1);
+
+} /* end of Cudd_EqualSupNorm */
+
+
+/**Function********************************************************************
+
+ Synopsis [Expands cube to a prime implicant of f.]
+
+ Description [Expands cube to a prime implicant of f. Returns the prime
+ if successful; NULL otherwise. In particular, NULL is returned if cube
+ is not a real cube or is not an implicant of f.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_bddMakePrime(
+ DdManager *dd /* manager */,
+ DdNode *cube /* cube to be expanded */,
+ DdNode *f /* function of which the cube is to be made a prime */)
+{
+ DdNode *res;
+
+ if (!Cudd_bddLeq(dd,cube,f)) return(NULL);
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddMakePrime(dd,cube,f);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddMakePrime */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddMakePrime.]
+
+ Description [Performs the recursive step of Cudd_bddMakePrime.
+ Returns the prime if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+cuddBddMakePrime(
+ DdManager *dd /* manager */,
+ DdNode *cube /* cube to be expanded */,
+ DdNode *f /* function of which the cube is to be made a prime */)
+{
+ DdNode *scan;
+ DdNode *t, *e;
+ DdNode *res = cube;
+ DdNode *zero = Cudd_Not(DD_ONE(dd));
+
+ Cudd_Ref(res);
+ scan = cube;
+ while (!Cudd_IsConstant(scan)) {
+ DdNode *reg = Cudd_Regular(scan);
+ DdNode *var = dd->vars[reg->index];
+ DdNode *expanded = Cudd_bddExistAbstract(dd,res,var);
+ if (expanded == NULL) {
+ return(NULL);
+ }
+ Cudd_Ref(expanded);
+ if (Cudd_bddLeq(dd,expanded,f)) {
+ Cudd_RecursiveDeref(dd,res);
+ res = expanded;
+ } else {
+ Cudd_RecursiveDeref(dd,expanded);
+ }
+ cuddGetBranches(scan,&t,&e);
+ if (t == zero) {
+ scan = e;
+ } else if (e == zero) {
+ scan = t;
+ } else {
+ Cudd_RecursiveDeref(dd,res);
+ return(NULL); /* cube is not a cube */
+ }
+ }
+
+ if (scan == DD_ONE(dd)) {
+ Cudd_Deref(res);
+ return(res);
+ } else {
+ Cudd_RecursiveDeref(dd,res);
+ return(NULL);
+ }
+
+} /* end of cuddBddMakePrime */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees the entries of the visited symbol table.]
+
+ Description [Frees the entries of the visited symbol table. Returns
+ ST_CONTINUE.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static enum st_retval
+freePathPair(
+ char * key,
+ char * value,
+ char * arg)
+{
+ cuddPathPair *pair;
+
+ pair = (cuddPathPair *) value;
+ FREE(pair);
+ return(ST_CONTINUE);
+
+} /* end of freePathPair */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the length of the shortest path(s) in a DD.]
+
+ Description [Finds the length of the shortest path(s) in a DD.
+ Uses a local symbol table to store the lengths for each
+ node. Only the lengths for the regular nodes are entered in the table,
+ because those for the complement nodes are simply obtained by swapping
+ the two lenghts.
+ Returns a pair of lengths: the length of the shortest path to 1;
+ and the length of the shortest path to 0. This is done so as to take
+ complement arcs into account.]
+
+ SideEffects [Accumulates the support of the DD in support.]
+
+ SeeAlso []
+
+******************************************************************************/
+static cuddPathPair
+getShortest(
+ DdNode * root,
+ int * cost,
+ int * support,
+ st_table * visited)
+{
+ cuddPathPair *my_pair, res_pair, pair_T, pair_E;
+ DdNode *my_root, *T, *E;
+ int weight;
+
+ my_root = Cudd_Regular(root);
+
+ if (st_lookup(visited, (char *)my_root, (char **)&my_pair)) {
+ if (Cudd_IsComplement(root)) {
+ res_pair.pos = my_pair->neg;
+ res_pair.neg = my_pair->pos;
+ } else {
+ res_pair.pos = my_pair->pos;
+ res_pair.neg = my_pair->neg;
+ }
+ return(res_pair);
+ }
+
+ /* In the case of a BDD the following test is equivalent to
+ ** testing whether the BDD is the constant 1. This formulation,
+ ** however, works for ADDs as well, by assuming the usual
+ ** dichotomy of 0 and != 0.
+ */
+ if (cuddIsConstant(my_root)) {
+ if (my_root != zero) {
+ res_pair.pos = 0;
+ res_pair.neg = DD_BIGGY;
+ } else {
+ res_pair.pos = DD_BIGGY;
+ res_pair.neg = 0;
+ }
+ } else {
+ T = cuddT(my_root);
+ E = cuddE(my_root);
+
+ pair_T = getShortest(T, cost, support, visited);
+ pair_E = getShortest(E, cost, support, visited);
+ weight = WEIGHT(cost, my_root->index);
+ res_pair.pos = ddMin(pair_T.pos+weight, pair_E.pos);
+ res_pair.neg = ddMin(pair_T.neg+weight, pair_E.neg);
+
+ /* Update support. */
+ if (support != NULL) {
+ support[my_root->index] = 1;
+ }
+ }
+
+ my_pair = ALLOC(cuddPathPair, 1);
+ if (my_pair == NULL) {
+ if (Cudd_IsComplement(root)) {
+ int tmp = res_pair.pos;
+ res_pair.pos = res_pair.neg;
+ res_pair.neg = tmp;
+ }
+ return(res_pair);
+ }
+ my_pair->pos = res_pair.pos;
+ my_pair->neg = res_pair.neg;
+
+ st_insert(visited, (char *)my_root, (char *)my_pair);
+ if (Cudd_IsComplement(root)) {
+ res_pair.pos = my_pair->neg;
+ res_pair.neg = my_pair->pos;
+ } else {
+ res_pair.pos = my_pair->pos;
+ res_pair.neg = my_pair->neg;
+ }
+ return(res_pair);
+
+} /* end of getShortest */
+
+
+/**Function********************************************************************
+
+ Synopsis [Build a BDD for a shortest path of f.]
+
+ Description [Build a BDD for a shortest path of f.
+ Given the minimum length from the root, and the minimum
+ lengths for each node (in visited), apply triangulation at each node.
+ Of the two children of each node on a shortest path, at least one is
+ on a shortest path. In case of ties the procedure chooses the THEN
+ children.
+ Returns a pointer to the cube BDD representing the path if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+getPath(
+ DdManager * manager,
+ st_table * visited,
+ DdNode * f,
+ int * weight,
+ int cost)
+{
+ DdNode *sol, *tmp;
+ DdNode *my_dd, *T, *E;
+ cuddPathPair *T_pair, *E_pair;
+ int Tcost, Ecost;
+ int complement;
+
+ my_dd = Cudd_Regular(f);
+ complement = Cudd_IsComplement(f);
+
+ sol = one;
+ cuddRef(sol);
+
+ while (!cuddIsConstant(my_dd)) {
+ Tcost = cost - WEIGHT(weight, my_dd->index);
+ Ecost = cost;
+
+ T = cuddT(my_dd);
+ E = cuddE(my_dd);
+
+ if (complement) {T = Cudd_Not(T); E = Cudd_Not(E);}
+
+ st_lookup(visited, (char *)Cudd_Regular(T), (char **)&T_pair);
+ if ((Cudd_IsComplement(T) && T_pair->neg == Tcost) ||
+ (!Cudd_IsComplement(T) && T_pair->pos == Tcost)) {
+ tmp = cuddBddAndRecur(manager,manager->vars[my_dd->index],sol);
+ if (tmp == NULL) {
+ Cudd_RecursiveDeref(manager,sol);
+ return(NULL);
+ }
+ cuddRef(tmp);
+ Cudd_RecursiveDeref(manager,sol);
+ sol = tmp;
+
+ complement = Cudd_IsComplement(T);
+ my_dd = Cudd_Regular(T);
+ cost = Tcost;
+ continue;
+ }
+ st_lookup(visited, (char *)Cudd_Regular(E), (char **)&E_pair);
+ if ((Cudd_IsComplement(E) && E_pair->neg == Ecost) ||
+ (!Cudd_IsComplement(E) && E_pair->pos == Ecost)) {
+ tmp = cuddBddAndRecur(manager,Cudd_Not(manager->vars[my_dd->index]),sol);
+ if (tmp == NULL) {
+ Cudd_RecursiveDeref(manager,sol);
+ return(NULL);
+ }
+ cuddRef(tmp);
+ Cudd_RecursiveDeref(manager,sol);
+ sol = tmp;
+ complement = Cudd_IsComplement(E);
+ my_dd = Cudd_Regular(E);
+ cost = Ecost;
+ continue;
+ }
+ (void) fprintf(manager->err,"We shouldn't be here!!\n");
+ manager->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+
+ cuddDeref(sol);
+ return(sol);
+
+} /* end of getPath */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the size of the largest cube(s) in a DD.]
+
+ Description [Finds the size of the largest cube(s) in a DD.
+ This problem is translated into finding the shortest paths from a node
+ when both THEN and ELSE arcs have unit lengths.
+ Uses a local symbol table to store the lengths for each
+ node. Only the lengths for the regular nodes are entered in the table,
+ because those for the complement nodes are simply obtained by swapping
+ the two lenghts.
+ Returns a pair of lengths: the length of the shortest path to 1;
+ and the length of the shortest path to 0. This is done so as to take
+ complement arcs into account.]
+
+ SideEffects [none]
+
+ SeeAlso []
+
+******************************************************************************/
+static cuddPathPair
+getLargest(
+ DdNode * root,
+ st_table * visited)
+{
+ cuddPathPair *my_pair, res_pair, pair_T, pair_E;
+ DdNode *my_root, *T, *E;
+
+ my_root = Cudd_Regular(root);
+
+ if (st_lookup(visited, (char *)my_root, (char **)&my_pair)) {
+ if (Cudd_IsComplement(root)) {
+ res_pair.pos = my_pair->neg;
+ res_pair.neg = my_pair->pos;
+ } else {
+ res_pair.pos = my_pair->pos;
+ res_pair.neg = my_pair->neg;
+ }
+ return(res_pair);
+ }
+
+ /* In the case of a BDD the following test is equivalent to
+ ** testing whether the BDD is the constant 1. This formulation,
+ ** however, works for ADDs as well, by assuming the usual
+ ** dichotomy of 0 and != 0.
+ */
+ if (cuddIsConstant(my_root)) {
+ if (my_root != zero) {
+ res_pair.pos = 0;
+ res_pair.neg = DD_BIGGY;
+ } else {
+ res_pair.pos = DD_BIGGY;
+ res_pair.neg = 0;
+ }
+ } else {
+ T = cuddT(my_root);
+ E = cuddE(my_root);
+
+ pair_T = getLargest(T, visited);
+ pair_E = getLargest(E, visited);
+ res_pair.pos = ddMin(pair_T.pos, pair_E.pos) + 1;
+ res_pair.neg = ddMin(pair_T.neg, pair_E.neg) + 1;
+ }
+
+ my_pair = ALLOC(cuddPathPair, 1);
+ if (my_pair == NULL) { /* simlpy do not cache this result */
+ if (Cudd_IsComplement(root)) {
+ int tmp = res_pair.pos;
+ res_pair.pos = res_pair.neg;
+ res_pair.neg = tmp;
+ }
+ return(res_pair);
+ }
+ my_pair->pos = res_pair.pos;
+ my_pair->neg = res_pair.neg;
+
+ st_insert(visited, (char *)my_root, (char *)my_pair);
+ if (Cudd_IsComplement(root)) {
+ res_pair.pos = my_pair->neg;
+ res_pair.neg = my_pair->pos;
+ } else {
+ res_pair.pos = my_pair->pos;
+ res_pair.neg = my_pair->neg;
+ }
+ return(res_pair);
+
+} /* end of getLargest */
+
+
+/**Function********************************************************************
+
+ Synopsis [Build a BDD for a largest cube of f.]
+
+ Description [Build a BDD for a largest cube of f.
+ Given the minimum length from the root, and the minimum
+ lengths for each node (in visited), apply triangulation at each node.
+ Of the two children of each node on a shortest path, at least one is
+ on a shortest path. In case of ties the procedure chooses the THEN
+ children.
+ Returns a pointer to the cube BDD representing the path if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+getCube(
+ DdManager * manager,
+ st_table * visited,
+ DdNode * f,
+ int cost)
+{
+ DdNode *sol, *tmp;
+ DdNode *my_dd, *T, *E;
+ cuddPathPair *T_pair, *E_pair;
+ int Tcost, Ecost;
+ int complement;
+
+ my_dd = Cudd_Regular(f);
+ complement = Cudd_IsComplement(f);
+
+ sol = one;
+ cuddRef(sol);
+
+ while (!cuddIsConstant(my_dd)) {
+ Tcost = cost - 1;
+ Ecost = cost - 1;
+
+ T = cuddT(my_dd);
+ E = cuddE(my_dd);
+
+ if (complement) {T = Cudd_Not(T); E = Cudd_Not(E);}
+
+ st_lookup(visited, (char *)Cudd_Regular(T), (char **)&T_pair);
+ if ((Cudd_IsComplement(T) && T_pair->neg == Tcost) ||
+ (!Cudd_IsComplement(T) && T_pair->pos == Tcost)) {
+ tmp = cuddBddAndRecur(manager,manager->vars[my_dd->index],sol);
+ if (tmp == NULL) {
+ Cudd_RecursiveDeref(manager,sol);
+ return(NULL);
+ }
+ cuddRef(tmp);
+ Cudd_RecursiveDeref(manager,sol);
+ sol = tmp;
+
+ complement = Cudd_IsComplement(T);
+ my_dd = Cudd_Regular(T);
+ cost = Tcost;
+ continue;
+ }
+ st_lookup(visited, (char *)Cudd_Regular(E), (char **)&E_pair);
+ if ((Cudd_IsComplement(E) && E_pair->neg == Ecost) ||
+ (!Cudd_IsComplement(E) && E_pair->pos == Ecost)) {
+ tmp = cuddBddAndRecur(manager,Cudd_Not(manager->vars[my_dd->index]),sol);
+ if (tmp == NULL) {
+ Cudd_RecursiveDeref(manager,sol);
+ return(NULL);
+ }
+ cuddRef(tmp);
+ Cudd_RecursiveDeref(manager,sol);
+ sol = tmp;
+ complement = Cudd_IsComplement(E);
+ my_dd = Cudd_Regular(E);
+ cost = Ecost;
+ continue;
+ }
+ (void) fprintf(manager->err,"We shouldn't be here!\n");
+ manager->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+
+ cuddDeref(sol);
+ return(sol);
+
+} /* end of getCube */
diff --git a/src/bdd/cudd/cuddSign.c b/src/bdd/cudd/cuddSign.c
new file mode 100644
index 00000000..62477e7f
--- /dev/null
+++ b/src/bdd/cudd/cuddSign.c
@@ -0,0 +1,292 @@
+/**CFile***********************************************************************
+
+ FileName [cuddSign.c]
+
+ PackageName [cudd]
+
+ Synopsis [Computation of signatures]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_CofMinterm();
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> ddCofMintermAux()
+ </ul>
+ ]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddSign.c,v 1.1.1.1 2003/02/24 22:23:53 wjiang Exp $";
+#endif
+
+static int size;
+
+#ifdef DD_STATS
+static int num_calls; /* should equal 2n-1 (n is the # of nodes) */
+static int table_mem;
+#endif
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static double * ddCofMintermAux ARGS((DdManager *dd, DdNode *node, st_table *table));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Computes the fraction of minterms in the on-set of all the
+ positive cofactors of a BDD or ADD.]
+
+ Description [Computes the fraction of minterms in the on-set of all
+ the positive cofactors of DD. Returns the pointer to an array of
+ doubles if successful; NULL otherwise. The array hs as many
+ positions as there are BDD variables in the manager plus one. The
+ last position of the array contains the fraction of the minterms in
+ the ON-set of the function represented by the BDD or ADD. The other
+ positions of the array hold the variable signatures.]
+
+ SideEffects [None]
+
+******************************************************************************/
+double *
+Cudd_CofMinterm(
+ DdManager * dd,
+ DdNode * node)
+{
+ st_table *table;
+ double *values;
+ double *result = NULL;
+ int i, firstLevel;
+
+#ifdef DD_STATS
+ long startTime;
+ startTime = util_cpu_time();
+ num_calls = 0;
+ table_mem = sizeof(st_table);
+#endif
+
+ table = st_init_table(st_ptrcmp, st_ptrhash);
+ if (table == NULL) {
+ (void) fprintf(dd->err,
+ "out-of-memory, couldn't measure DD cofactors.\n");
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ size = dd->size;
+ values = ddCofMintermAux(dd, node, table);
+ if (values != NULL) {
+ result = ALLOC(double,size + 1);
+ if (result != NULL) {
+#ifdef DD_STATS
+ table_mem += (size + 1) * sizeof(double);
+#endif
+ if (Cudd_IsConstant(node))
+ firstLevel = 1;
+ else
+ firstLevel = cuddI(dd,Cudd_Regular(node)->index);
+ for (i = 0; i < size; i++) {
+ if (i >= cuddI(dd,Cudd_Regular(node)->index)) {
+ result[dd->invperm[i]] = values[i - firstLevel];
+ } else {
+ result[dd->invperm[i]] = values[size - firstLevel];
+ }
+ }
+ result[size] = values[size - firstLevel];
+ } else {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ }
+ }
+
+#ifdef DD_STATS
+ table_mem += table->num_bins * sizeof(st_table_entry *);
+#endif
+ if (Cudd_Regular(node)->ref == 1) FREE(values);
+ st_foreach(table, cuddStCountfree, NULL);
+ st_free_table(table);
+#ifdef DD_STATS
+ (void) fprintf(dd->out,"Number of calls: %d\tTable memory: %d bytes\n",
+ num_calls, table_mem);
+ (void) fprintf(dd->out,"Time to compute measures: %s\n",
+ util_print_time(util_cpu_time() - startTime));
+#endif
+ if (result == NULL) {
+ (void) fprintf(dd->out,
+ "out-of-memory, couldn't measure DD cofactors.\n");
+ dd->errorCode = CUDD_MEMORY_OUT;
+ }
+ return(result);
+
+} /* end of Cudd_CofMinterm */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Recursive Step for Cudd_CofMinterm function.]
+
+ Description [Traverses the DD node and computes the fraction of
+ minterms in the on-set of all positive cofactors simultaneously.
+ It allocates an array with two more entries than there are
+ variables below the one labeling the node. One extra entry (the
+ first in the array) is for the variable labeling the node. The other
+ entry (the last one in the array) holds the fraction of minterms of
+ the function rooted at node. Each other entry holds the value for
+ one cofactor. The array is put in a symbol table, to avoid repeated
+ computation, and its address is returned by the procedure, for use
+ by the caller. Returns a pointer to the array of cofactor measures.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static double *
+ddCofMintermAux(
+ DdManager * dd,
+ DdNode * node,
+ st_table * table)
+{
+ DdNode *N; /* regular version of node */
+ DdNode *Nv, *Nnv;
+ double *values;
+ double *valuesT, *valuesE;
+ int i;
+ int localSize, localSizeT, localSizeE;
+ double vT, vE;
+
+ statLine(dd);
+#ifdef DD_STATS
+ num_calls++;
+#endif
+
+ if (st_lookup(table, (char *) node, (char **) &values)) {
+ return(values);
+ }
+
+ N = Cudd_Regular(node);
+ if (cuddIsConstant(N)) {
+ localSize = 1;
+ } else {
+ localSize = size - cuddI(dd,N->index) + 1;
+ }
+ values = ALLOC(double, localSize);
+ if (values == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+
+ if (cuddIsConstant(N)) {
+ if (node == DD_ZERO(dd) || node == Cudd_Not(DD_ONE(dd))) {
+ values[0] = 0.0;
+ } else {
+ values[0] = 1.0;
+ }
+ } else {
+ Nv = Cudd_NotCond(cuddT(N),N!=node);
+ Nnv = Cudd_NotCond(cuddE(N),N!=node);
+
+ valuesT = ddCofMintermAux(dd, Nv, table);
+ if (valuesT == NULL) return(NULL);
+ valuesE = ddCofMintermAux(dd, Nnv, table);
+ if (valuesE == NULL) return(NULL);
+
+ if (Cudd_IsConstant(Nv)) {
+ localSizeT = 1;
+ } else {
+ localSizeT = size - cuddI(dd,Cudd_Regular(Nv)->index) + 1;
+ }
+ if (Cudd_IsConstant(Nnv)) {
+ localSizeE = 1;
+ } else {
+ localSizeE = size - cuddI(dd,Cudd_Regular(Nnv)->index) + 1;
+ }
+ values[0] = valuesT[localSizeT - 1];
+ for (i = 1; i < localSize; i++) {
+ if (i >= cuddI(dd,Cudd_Regular(Nv)->index) - cuddI(dd,N->index)) {
+ vT = valuesT[i - cuddI(dd,Cudd_Regular(Nv)->index) +
+ cuddI(dd,N->index)];
+ } else {
+ vT = valuesT[localSizeT - 1];
+ }
+ if (i >= cuddI(dd,Cudd_Regular(Nnv)->index) - cuddI(dd,N->index)) {
+ vE = valuesE[i - cuddI(dd,Cudd_Regular(Nnv)->index) +
+ cuddI(dd,N->index)];
+ } else {
+ vE = valuesE[localSizeE - 1];
+ }
+ values[i] = (vT + vE) / 2.0;
+ }
+ if (Cudd_Regular(Nv)->ref == 1) FREE(valuesT);
+ if (Cudd_Regular(Nnv)->ref == 1) FREE(valuesE);
+ }
+
+ if (N->ref > 1) {
+ if (st_add_direct(table, (char *) node, (char *) values) == ST_OUT_OF_MEM) {
+ FREE(values);
+ return(NULL);
+ }
+#ifdef DD_STATS
+ table_mem += localSize * sizeof(double) + sizeof(st_table_entry);
+#endif
+ }
+ return(values);
+
+} /* end of ddCofMintermAux */
+
diff --git a/src/bdd/cudd/cuddSolve.c b/src/bdd/cudd/cuddSolve.c
new file mode 100644
index 00000000..058e0c08
--- /dev/null
+++ b/src/bdd/cudd/cuddSolve.c
@@ -0,0 +1,339 @@
+/**CFile***********************************************************************
+
+ FileName [cuddSolve.c]
+
+ PackageName [cudd]
+
+ Synopsis [Boolean equation solver and related functions.]
+
+ Description [External functions included in this modoule:
+ <ul>
+ <li> Cudd_SolveEqn()
+ <li> Cudd_VerifySol()
+ </ul>
+ Internal functions included in this module:
+ <ul>
+ <li> cuddSolveEqnRecur()
+ <li> cuddVerifySol()
+ </ul> ]
+
+ SeeAlso []
+
+ Author [Balakrishna Kumthekar]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Structure declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddSolve.c,v 1.1.1.1 2003/02/24 22:23:53 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the solution of F(x,y) = 0.]
+
+ Description [Implements the solution for F(x,y) = 0. The return
+ value is the consistency condition. The y variables are the unknowns
+ and the remaining variables are the parameters. Returns the
+ consistency condition if successful; NULL otherwise. Cudd_SolveEqn
+ allocates an array and fills it with the indices of the
+ unknowns. This array is used by Cudd_VerifySol.]
+
+ SideEffects [The solution is returned in G; the indices of the y
+ variables are returned in yIndex.]
+
+ SeeAlso [Cudd_VerifySol]
+
+******************************************************************************/
+DdNode *
+Cudd_SolveEqn(
+ DdManager * bdd,
+ DdNode * F /* the left-hand side of the equation */,
+ DdNode * Y /* the cube of the y variables */,
+ DdNode ** G /* the array of solutions (return parameter) */,
+ int ** yIndex /* index of y variables */,
+ int n /* numbers of unknowns */)
+{
+ DdNode *res;
+ int *temp;
+
+ *yIndex = temp = ALLOC(int, n);
+ if (temp == NULL) {
+ bdd->errorCode = CUDD_MEMORY_OUT;
+ (void) fprintf(bdd->out,
+ "Cudd_SolveEqn: Out of memory for yIndex\n");
+ return(NULL);
+ }
+
+ do {
+ bdd->reordered = 0;
+ res = cuddSolveEqnRecur(bdd, F, Y, G, n, temp, 0);
+ } while (bdd->reordered == 1);
+
+ return(res);
+
+} /* end of Cudd_SolveEqn */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks the solution of F(x,y) = 0.]
+
+ Description [Checks the solution of F(x,y) = 0. This procedure
+ substitutes the solution components for the unknowns of F and returns
+ the resulting BDD for F.]
+
+ SideEffects [Frees the memory pointed by yIndex.]
+
+ SeeAlso [Cudd_SolveEqn]
+
+******************************************************************************/
+DdNode *
+Cudd_VerifySol(
+ DdManager * bdd,
+ DdNode * F /* the left-hand side of the equation */,
+ DdNode ** G /* the array of solutions */,
+ int * yIndex /* index of y variables */,
+ int n /* numbers of unknowns */)
+{
+ DdNode *res;
+
+ do {
+ bdd->reordered = 0;
+ res = cuddVerifySol(bdd, F, G, yIndex, n);
+ } while (bdd->reordered == 1);
+
+ FREE(yIndex);
+
+ return(res);
+
+} /* end of Cudd_VerifySol */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_SolveEqn.]
+
+ Description [Implements the recursive step of Cudd_SolveEqn.
+ Returns NULL if the intermediate solution blows up
+ or reordering occurs. The parametric solutions are
+ stored in the array G.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_SolveEqn, Cudd_VerifySol]
+
+******************************************************************************/
+DdNode *
+cuddSolveEqnRecur(
+ DdManager * bdd,
+ DdNode * F /* the left-hand side of the equation */,
+ DdNode * Y /* the cube of remaining y variables */,
+ DdNode ** G /* the array of solutions */,
+ int n /* number of unknowns */,
+ int * yIndex /* array holding the y variable indices */,
+ int i /* level of recursion */)
+{
+ DdNode *Fn, *Fm1, *Fv, *Fvbar, *T, *w, *nextY, *one;
+ DdNodePtr *variables;
+
+ int j;
+
+ statLine(bdd);
+ variables = bdd->vars;
+ one = DD_ONE(bdd);
+
+ /* Base condition. */
+ if (Y == one) {
+ return F;
+ }
+
+ /* Cofactor of Y. */
+ yIndex[i] = Y->index;
+ nextY = Cudd_T(Y);
+
+ /* Universal abstraction of F with respect to the top variable index. */
+ Fm1 = cuddBddExistAbstractRecur(bdd, Cudd_Not(F), variables[yIndex[i]]);
+ if (Fm1) {
+ Fm1 = Cudd_Not(Fm1);
+ cuddRef(Fm1);
+ } else {
+ return(NULL);
+ }
+
+ Fn = cuddSolveEqnRecur(bdd, Fm1, nextY, G, n, yIndex, i+1);
+ if (Fn) {
+ cuddRef(Fn);
+ } else {
+ Cudd_RecursiveDeref(bdd, Fm1);
+ return(NULL);
+ }
+
+ Fv = cuddCofactorRecur(bdd, F, variables[yIndex[i]]);
+ if (Fv) {
+ cuddRef(Fv);
+ } else {
+ Cudd_RecursiveDeref(bdd, Fm1);
+ Cudd_RecursiveDeref(bdd, Fn);
+ return(NULL);
+ }
+
+ Fvbar = cuddCofactorRecur(bdd, F, Cudd_Not(variables[yIndex[i]]));
+ if (Fvbar) {
+ cuddRef(Fvbar);
+ } else {
+ Cudd_RecursiveDeref(bdd, Fm1);
+ Cudd_RecursiveDeref(bdd, Fn);
+ Cudd_RecursiveDeref(bdd, Fv);
+ return(NULL);
+ }
+
+ /* Build i-th component of the solution. */
+ w = cuddBddIteRecur(bdd, variables[yIndex[i]], Cudd_Not(Fv), Fvbar);
+ if (w) {
+ cuddRef(w);
+ } else {
+ Cudd_RecursiveDeref(bdd, Fm1);
+ Cudd_RecursiveDeref(bdd, Fn);
+ Cudd_RecursiveDeref(bdd, Fv);
+ Cudd_RecursiveDeref(bdd, Fvbar);
+ return(NULL);
+ }
+
+ T = cuddBddRestrictRecur(bdd, w, Cudd_Not(Fm1));
+ if(T) {
+ cuddRef(T);
+ } else {
+ Cudd_RecursiveDeref(bdd, Fm1);
+ Cudd_RecursiveDeref(bdd, Fn);
+ Cudd_RecursiveDeref(bdd, Fv);
+ Cudd_RecursiveDeref(bdd, Fvbar);
+ Cudd_RecursiveDeref(bdd, w);
+ return(NULL);
+ }
+
+ Cudd_RecursiveDeref(bdd,Fm1);
+ Cudd_RecursiveDeref(bdd,w);
+ Cudd_RecursiveDeref(bdd,Fv);
+ Cudd_RecursiveDeref(bdd,Fvbar);
+
+ /* Substitute components of solution already found into solution. */
+ for (j = n-1; j > i; j--) {
+ w = cuddBddComposeRecur(bdd,T, G[j], variables[yIndex[j]]);
+ if(w) {
+ cuddRef(w);
+ } else {
+ Cudd_RecursiveDeref(bdd, Fn);
+ Cudd_RecursiveDeref(bdd, T);
+ return(NULL);
+ }
+ Cudd_RecursiveDeref(bdd,T);
+ T = w;
+ }
+ G[i] = T;
+
+ Cudd_Deref(Fn);
+
+ return(Fn);
+
+} /* end of cuddSolveEqnRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_VerifySol. ]
+
+ Description []
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_VerifySol]
+
+******************************************************************************/
+DdNode *
+cuddVerifySol(
+ DdManager * bdd,
+ DdNode * F /* the left-hand side of the equation */,
+ DdNode ** G /* the array of solutions */,
+ int * yIndex /* array holding the y variable indices */,
+ int n /* number of unknowns */)
+{
+ DdNode *w, *R;
+
+ int j;
+
+ R = F;
+ cuddRef(R);
+ for(j = n - 1; j >= 0; j--) {
+ w = Cudd_bddCompose(bdd, R, G[j], yIndex[j]);
+ if (w) {
+ cuddRef(w);
+ } else {
+ return(NULL);
+ }
+ Cudd_RecursiveDeref(bdd,R);
+ R = w;
+ }
+
+ cuddDeref(R);
+
+ return(R);
+
+} /* end of cuddVerifySol */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
diff --git a/src/bdd/cudd/cuddSplit.c b/src/bdd/cudd/cuddSplit.c
new file mode 100644
index 00000000..af7d6372
--- /dev/null
+++ b/src/bdd/cudd/cuddSplit.c
@@ -0,0 +1,657 @@
+/**CFile***********************************************************************
+
+ FileName [cuddSplit.c]
+
+ PackageName [cudd]
+
+ Synopsis [Returns a subset of minterms from a boolean function.]
+
+ Description [External functions included in this modoule:
+ <ul>
+ <li> Cudd_SplitSet()
+ </ul>
+ Internal functions included in this module:
+ <ul>
+ <li> cuddSplitSetRecur()
+ </u>
+ Static functions included in this module:
+ <ul>
+ <li> selectMintermsFromUniverse()
+ <li> mintermsFromUniverse()
+ <li> bddAnnotateMintermCount()
+ </ul> ]
+
+ SeeAlso []
+
+ Author [Balakrishna Kumthekar]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Structure declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static DdNode * selectMintermsFromUniverse ARGS((DdManager *manager, int *varSeen, double n));
+static DdNode * mintermsFromUniverse ARGS((DdManager *manager, DdNode **vars, int numVars, double n, int index));
+static double bddAnnotateMintermCount ARGS((DdManager *manager, DdNode *node, double max, st_table *table));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns m minterms from a BDD.]
+
+ Description [Returns <code>m</code> minterms from a BDD whose
+ support has <code>n</code> variables at most. The procedure tries
+ to create as few extra nodes as possible. The function represented
+ by <code>S</code> depends on at most <code>n</code> of the variables
+ in <code>xVars</code>. Returns a BDD with <code>m</code> minterms
+ of the on-set of S if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_SplitSet(
+ DdManager * manager,
+ DdNode * S,
+ DdNode ** xVars,
+ int n,
+ double m)
+{
+ DdNode *result;
+ DdNode *zero, *one;
+ double max, num;
+ st_table *mtable;
+ int *varSeen;
+ int i,index, size;
+
+ size = manager->size;
+ one = DD_ONE(manager);
+ zero = Cudd_Not(one);
+
+ /* Trivial cases. */
+ if (m == 0.0) {
+ return(zero);
+ }
+ if (S == zero) {
+ return(NULL);
+ }
+
+ max = pow(2.0,(double)n);
+ if (m > max)
+ return(NULL);
+
+ do {
+ manager->reordered = 0;
+ /* varSeen is used to mark the variables that are encountered
+ ** while traversing the BDD S.
+ */
+ varSeen = ALLOC(int, size);
+ if (varSeen == NULL) {
+ manager->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < size; i++) {
+ varSeen[i] = -1;
+ }
+ for (i = 0; i < n; i++) {
+ index = (xVars[i])->index;
+ varSeen[manager->invperm[index]] = 0;
+ }
+
+ if (S == one) {
+ if (m == max)
+ return(S);
+ result = selectMintermsFromUniverse(manager,varSeen,m);
+ if (result)
+ cuddRef(result);
+ FREE(varSeen);
+ } else {
+ mtable = st_init_table(st_ptrcmp,st_ptrhash);
+ if (mtable == NULL) {
+ (void) fprintf(manager->out,
+ "Cudd_SplitSet: out-of-memory.\n");
+ FREE(varSeen);
+ manager->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ /* The nodes of BDD S are annotated by the number of minterms
+ ** in their onset. The node and the number of minterms in its
+ ** onset are stored in mtable.
+ */
+ num = bddAnnotateMintermCount(manager,S,max,mtable);
+ if (m == num) {
+ st_foreach(mtable,cuddStCountfree,NIL(char));
+ st_free_table(mtable);
+ FREE(varSeen);
+ return(S);
+ }
+
+ result = cuddSplitSetRecur(manager,mtable,varSeen,S,m,max,0);
+ if (result)
+ cuddRef(result);
+ st_foreach(mtable,cuddStCountfree,NULL);
+ st_free_table(mtable);
+ FREE(varSeen);
+ }
+ } while (manager->reordered == 1);
+
+ cuddDeref(result);
+ return(result);
+
+} /* end of Cudd_SplitSet */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_SplitSet.]
+
+ Description [Implements the recursive step of Cudd_SplitSet. The
+ procedure recursively traverses the BDD and checks to see if any
+ node satisfies the minterm requirements as specified by 'n'. At any
+ node X, n is compared to the number of minterms in the onset of X's
+ children. If either of the child nodes have exactly n minterms, then
+ that node is returned; else, if n is greater than the onset of one
+ of the child nodes, that node is retained and the difference in the
+ number of minterms is extracted from the other child. In case n
+ minterms can be extracted from constant 1, the algorithm returns the
+ result with at most log(n) nodes.]
+
+ SideEffects [The array 'varSeen' is updated at every recursive call
+ to set the variables traversed by the procedure.]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode*
+cuddSplitSetRecur(
+ DdManager * manager,
+ st_table * mtable,
+ int * varSeen,
+ DdNode * p,
+ double n,
+ double max,
+ int index)
+{
+ DdNode *one, *zero, *N, *Nv;
+ DdNode *Nnv, *q, *r, *v;
+ DdNode *result;
+ double *dummy, numT, numE;
+ int variable, positive;
+
+ statLine(manager);
+ one = DD_ONE(manager);
+ zero = Cudd_Not(one);
+
+ /* If p is constant, extract n minterms from constant 1. The procedure by
+ ** construction guarantees that minterms will not be extracted from
+ ** constant 0.
+ */
+ if (Cudd_IsConstant(p)) {
+ q = selectMintermsFromUniverse(manager,varSeen,n);
+ return(q);
+ }
+
+ N = Cudd_Regular(p);
+
+ /* Set variable as seen. */
+ variable = N->index;
+ varSeen[manager->invperm[variable]] = -1;
+
+ Nv = cuddT(N);
+ Nnv = cuddE(N);
+ if (Cudd_IsComplement(p)) {
+ Nv = Cudd_Not(Nv);
+ Nnv = Cudd_Not(Nnv);
+ }
+
+ /* If both the children of 'p' are constants, extract n minterms from a
+ ** constant node.
+ */
+ if (Cudd_IsConstant(Nv) && Cudd_IsConstant(Nnv)) {
+ q = selectMintermsFromUniverse(manager,varSeen,n);
+ if (q == NULL) {
+ return(NULL);
+ }
+ cuddRef(q);
+ r = cuddBddAndRecur(manager,p,q);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(manager,q);
+ return(NULL);
+ }
+ cuddRef(r);
+ Cudd_RecursiveDeref(manager,q);
+ cuddDeref(r);
+ return(r);
+ }
+
+ /* Lookup the # of minterms in the onset of the node from the table. */
+ if (!Cudd_IsConstant(Nv)) {
+ st_lookup(mtable,(char *)Nv, (char **)&dummy);
+ numT = *dummy/(2*(1<<index));
+ } else if (Nv == one) {
+ numT = max/(2*(1<<index));
+ } else {
+ numT = 0;
+ }
+
+ if (!Cudd_IsConstant(Nnv)) {
+ st_lookup(mtable,(char *)Nnv, (char **)&dummy);
+ numE = *dummy/(2*(1<<index));
+ } else if (Nnv == one) {
+ numE = max/(2*(1<<index));
+ } else {
+ numE = 0;
+ }
+
+ v = cuddUniqueInter(manager,variable,one,zero);
+ cuddRef(v);
+
+ /* If perfect match. */
+ if (numT == n) {
+ q = cuddBddAndRecur(manager,v,Nv);
+ if (q == NULL) {
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(q);
+ Cudd_RecursiveDeref(manager,v);
+ cuddDeref(q);
+ return(q);
+ }
+ if (numE == n) {
+ q = cuddBddAndRecur(manager,Cudd_Not(v),Nnv);
+ if (q == NULL) {
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(q);
+ Cudd_RecursiveDeref(manager,v);
+ cuddDeref(q);
+ return(q);
+ }
+ /* If n is greater than numT, extract the difference from the ELSE child
+ ** and retain the function represented by the THEN branch.
+ */
+ if (numT < n) {
+ q = cuddSplitSetRecur(manager,mtable,varSeen,
+ Nnv,(n-numT),max,index+1);
+ if (q == NULL) {
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(q);
+ r = cuddBddIteRecur(manager,v,Nv,q);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(manager,q);
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(r);
+ Cudd_RecursiveDeref(manager,q);
+ Cudd_RecursiveDeref(manager,v);
+ cuddDeref(r);
+ return(r);
+ }
+ /* If n is greater than numE, extract the difference from the THEN child
+ ** and retain the function represented by the ELSE branch.
+ */
+ if (numE < n) {
+ q = cuddSplitSetRecur(manager,mtable,varSeen,
+ Nv, (n-numE),max,index+1);
+ if (q == NULL) {
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(q);
+ r = cuddBddIteRecur(manager,v,q,Nnv);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(manager,q);
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(r);
+ Cudd_RecursiveDeref(manager,q);
+ Cudd_RecursiveDeref(manager,v);
+ cuddDeref(r);
+ return(r);
+ }
+
+ /* None of the above cases; (n < numT and n < numE) and either of
+ ** the Nv, Nnv or both are not constants. If possible extract the
+ ** required minterms the constant branch.
+ */
+ if (Cudd_IsConstant(Nv) && !Cudd_IsConstant(Nnv)) {
+ q = selectMintermsFromUniverse(manager,varSeen,n);
+ if (q == NULL) {
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(q);
+ result = cuddBddAndRecur(manager,v,q);
+ if (result == NULL) {
+ Cudd_RecursiveDeref(manager,q);
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(result);
+ Cudd_RecursiveDeref(manager,q);
+ Cudd_RecursiveDeref(manager,v);
+ cuddDeref(result);
+ return(result);
+ } else if (!Cudd_IsConstant(Nv) && Cudd_IsConstant(Nnv)) {
+ q = selectMintermsFromUniverse(manager,varSeen,n);
+ if (q == NULL) {
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(q);
+ result = cuddBddAndRecur(manager,Cudd_Not(v),q);
+ if (result == NULL) {
+ Cudd_RecursiveDeref(manager,q);
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(result);
+ Cudd_RecursiveDeref(manager,q);
+ Cudd_RecursiveDeref(manager,v);
+ cuddDeref(result);
+ return(result);
+ }
+
+ /* Both Nv and Nnv are not constants. So choose the one which
+ ** has fewer minterms in its onset.
+ */
+ positive = 0;
+ if (numT < numE) {
+ q = cuddSplitSetRecur(manager,mtable,varSeen,
+ Nv,n,max,index+1);
+ positive = 1;
+ } else {
+ q = cuddSplitSetRecur(manager,mtable,varSeen,
+ Nnv,n,max,index+1);
+ }
+
+ if (q == NULL) {
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(q);
+
+ if (positive) {
+ result = cuddBddAndRecur(manager,v,q);
+ } else {
+ result = cuddBddAndRecur(manager,Cudd_Not(v),q);
+ }
+ if (result == NULL) {
+ Cudd_RecursiveDeref(manager,q);
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(result);
+ Cudd_RecursiveDeref(manager,q);
+ Cudd_RecursiveDeref(manager,v);
+ cuddDeref(result);
+
+ return(result);
+
+} /* end of cuddSplitSetRecur */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [This function prepares an array of variables which have not been
+ encountered so far when traversing the procedure cuddSplitSetRecur.]
+
+ Description [This function prepares an array of variables which have not been
+ encountered so far when traversing the procedure cuddSplitSetRecur. This
+ array is then used to extract the required number of minterms from a constant
+ 1. The algorithm guarantees that the size of BDD will be utmost \log(n).]
+
+ SideEffects [None]
+
+******************************************************************************/
+static DdNode *
+selectMintermsFromUniverse(
+ DdManager * manager,
+ int * varSeen,
+ double n)
+{
+ int numVars;
+ int i, size, j;
+ DdNode *one, *zero, *result;
+ DdNode **vars;
+
+ numVars = 0;
+ size = manager->size;
+ one = DD_ONE(manager);
+ zero = Cudd_Not(one);
+
+ /* Count the number of variables not encountered so far in procedure
+ ** cuddSplitSetRecur.
+ */
+ for (i = size-1; i >= 0; i--) {
+ if(varSeen[i] == 0)
+ numVars++;
+ }
+ vars = ALLOC(DdNode *, numVars);
+ if (!vars) {
+ manager->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+
+ j = 0;
+ for (i = size-1; i >= 0; i--) {
+ if(varSeen[i] == 0) {
+ vars[j] = cuddUniqueInter(manager,manager->perm[i],one,zero);
+ cuddRef(vars[j]);
+ j++;
+ }
+ }
+
+ /* Compute a function which has n minterms and depends on at most
+ ** numVars variables.
+ */
+ result = mintermsFromUniverse(manager,vars,numVars,n, 0);
+ if (result)
+ cuddRef(result);
+
+ for (i = 0; i < numVars; i++)
+ Cudd_RecursiveDeref(manager,vars[i]);
+ FREE(vars);
+
+ return(result);
+
+} /* end of selectMintermsFromUniverse */
+
+
+/**Function********************************************************************
+
+ Synopsis [Recursive procedure to extract n mintems from constant 1.]
+
+ Description [Recursive procedure to extract n mintems from constant 1.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static DdNode *
+mintermsFromUniverse(
+ DdManager * manager,
+ DdNode ** vars,
+ int numVars,
+ double n,
+ int index)
+{
+ DdNode *one, *zero;
+ DdNode *q, *result;
+ double max, max2;
+
+ statLine(manager);
+ one = DD_ONE(manager);
+ zero = Cudd_Not(one);
+
+ max = pow(2.0, (double)numVars);
+ max2 = max / 2.0;
+
+ if (n == max)
+ return(one);
+ if (n == 0.0)
+ return(zero);
+ /* if n == 2^(numVars-1), return a single variable */
+ if (n == max2)
+ return vars[index];
+ else if (n > max2) {
+ /* When n > 2^(numVars-1), a single variable vars[index]
+ ** contains 2^(numVars-1) minterms. The rest are extracted
+ ** from a constant with 1 less variable.
+ */
+ q = mintermsFromUniverse(manager,vars,numVars-1,(n-max2),index+1);
+ if (q == NULL)
+ return(NULL);
+ cuddRef(q);
+ result = cuddBddIteRecur(manager,vars[index],one,q);
+ } else {
+ /* When n < 2^(numVars-1), a literal of variable vars[index]
+ ** is selected. The required n minterms are extracted from a
+ ** constant with 1 less variable.
+ */
+ q = mintermsFromUniverse(manager,vars,numVars-1,n,index+1);
+ if (q == NULL)
+ return(NULL);
+ cuddRef(q);
+ result = cuddBddAndRecur(manager,vars[index],q);
+ }
+
+ if (result == NULL) {
+ Cudd_RecursiveDeref(manager,q);
+ return(NULL);
+ }
+ cuddRef(result);
+ Cudd_RecursiveDeref(manager,q);
+ cuddDeref(result);
+ return(result);
+
+} /* end of mintermsFromUniverse */
+
+
+/**Function********************************************************************
+
+ Synopsis [Annotates every node in the BDD node with its minterm count.]
+
+ Description [Annotates every node in the BDD node with its minterm count.
+ In this function, every node and the minterm count represented by it are
+ stored in a hash table.]
+
+ SideEffects [Fills up 'table' with the pair <node,minterm_count>.]
+
+******************************************************************************/
+static double
+bddAnnotateMintermCount(
+ DdManager * manager,
+ DdNode * node,
+ double max,
+ st_table * table)
+{
+
+ DdNode *N,*Nv,*Nnv;
+ register double min_v,min_nv;
+ register double min_N;
+ double *pmin;
+ double *dummy;
+
+ statLine(manager);
+ N = Cudd_Regular(node);
+ if (cuddIsConstant(N)) {
+ if (node == DD_ONE(manager)) {
+ return(max);
+ } else {
+ return(0.0);
+ }
+ }
+
+ if (st_lookup(table,(char *)node,(char **)&dummy)) {
+ return(*dummy);
+ }
+
+ Nv = cuddT(N);
+ Nnv = cuddE(N);
+ if (N != node) {
+ Nv = Cudd_Not(Nv);
+ Nnv = Cudd_Not(Nnv);
+ }
+
+ /* Recur on the two branches. */
+ min_v = bddAnnotateMintermCount(manager,Nv,max,table) / 2.0;
+ if (min_v == (double)CUDD_OUT_OF_MEM)
+ return ((double)CUDD_OUT_OF_MEM);
+ min_nv = bddAnnotateMintermCount(manager,Nnv,max,table) / 2.0;
+ if (min_nv == (double)CUDD_OUT_OF_MEM)
+ return ((double)CUDD_OUT_OF_MEM);
+ min_N = min_v + min_nv;
+
+ pmin = ALLOC(double,1);
+ if (pmin == NULL) {
+ manager->errorCode = CUDD_MEMORY_OUT;
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ *pmin = min_N;
+
+ if (st_insert(table,(char *)node, (char *)pmin) == ST_OUT_OF_MEM) {
+ FREE(pmin);
+ return((double)CUDD_OUT_OF_MEM);
+ }
+
+ return(min_N);
+
+} /* end of bddAnnotateMintermCount */
diff --git a/src/bdd/cudd/cuddSubsetHB.c b/src/bdd/cudd/cuddSubsetHB.c
new file mode 100644
index 00000000..43aaf744
--- /dev/null
+++ b/src/bdd/cudd/cuddSubsetHB.c
@@ -0,0 +1,1311 @@
+/**CFile***********************************************************************
+
+ FileName [cuddSubsetHB.c]
+
+ PackageName [cudd]
+
+ Synopsis [Procedure to subset the given BDD by choosing the heavier
+ branches]
+
+
+ Description [External procedures provided by this module:
+ <ul>
+ <li> Cudd_SubsetHeavyBranch()
+ <li> Cudd_SupersetHeavyBranch()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddSubsetHeavyBranch()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> ResizeCountMintermPages();
+ <li> ResizeNodeDataPages()
+ <li> ResizeCountNodePages()
+ <li> SubsetCountMintermAux()
+ <li> SubsetCountMinterm()
+ <li> SubsetCountNodesAux()
+ <li> SubsetCountNodes()
+ <li> BuildSubsetBdd()
+ </ul>
+ ]
+
+ SeeAlso [cuddSubsetSP.c]
+
+ Author [Kavita Ravi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no
+ warranty about the suitability of this software for any
+ purpose. It is presented on an AS IS basis.]
+
+******************************************************************************/
+
+#ifdef __STDC__
+#include <float.h>
+#else
+#define DBL_MAX_EXP 1024
+#endif
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define DEFAULT_PAGE_SIZE 2048
+#define DEFAULT_NODE_DATA_PAGE_SIZE 1024
+#define INITIAL_PAGES 128
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/* data structure to store the information on each node. It keeps
+ * the number of minterms represented by the DAG rooted at this node
+ * in terms of the number of variables specified by the user, number
+ * of nodes in this DAG and the number of nodes of its child with
+ * lesser number of minterms that are not shared by the child with
+ * more minterms
+ */
+struct NodeData {
+ double *mintermPointer;
+ int *nodesPointer;
+ int *lightChildNodesPointer;
+};
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+typedef struct NodeData NodeData_t;
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddSubsetHB.c,v 1.1.1.1 2003/02/24 22:23:53 wjiang Exp $";
+#endif
+
+static int memOut;
+#ifdef DEBUG
+static int num_calls;
+#endif
+
+static DdNode *zero, *one; /* constant functions */
+static double **mintermPages; /* pointers to the pages */
+static int **nodePages; /* pointers to the pages */
+static int **lightNodePages; /* pointers to the pages */
+static double *currentMintermPage; /* pointer to the current
+ page */
+static double max; /* to store the 2^n value of the number
+ * of variables */
+
+static int *currentNodePage; /* pointer to the current
+ page */
+static int *currentLightNodePage; /* pointer to the
+ * current page */
+static int pageIndex; /* index to next element */
+static int page; /* index to current page */
+static int pageSize = DEFAULT_PAGE_SIZE; /* page size */
+static int maxPages; /* number of page pointers */
+
+static NodeData_t *currentNodeDataPage; /* pointer to the current
+ page */
+static int nodeDataPage; /* index to next element */
+static int nodeDataPageIndex; /* index to next element */
+static NodeData_t **nodeDataPages; /* index to current page */
+static int nodeDataPageSize = DEFAULT_NODE_DATA_PAGE_SIZE;
+ /* page size */
+static int maxNodeDataPages; /* number of page pointers */
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static void ResizeNodeDataPages ARGS(());
+static void ResizeCountMintermPages ARGS(());
+static void ResizeCountNodePages ARGS(());
+static double SubsetCountMintermAux ARGS((DdNode *node, double max, st_table *table));
+static st_table * SubsetCountMinterm ARGS((DdNode *node, int nvars));
+static int SubsetCountNodesAux ARGS((DdNode *node, st_table *table, double max));
+static int SubsetCountNodes ARGS((DdNode *node, st_table *table, int nvars));
+static void StoreNodes ARGS((st_table *storeTable, DdManager *dd, DdNode *node));
+static DdNode * BuildSubsetBdd ARGS((DdManager *dd, DdNode *node, int *size, st_table *visitedTable, int threshold, st_table *storeTable, st_table *approxTable));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Extracts a dense subset from a BDD with the heavy branch
+ heuristic.]
+
+ Description [Extracts a dense subset from a BDD. This procedure
+ builds a subset by throwing away one of the children of each node,
+ starting from the root, until the result is small enough. The child
+ that is eliminated from the result is the one that contributes the
+ fewer minterms. Returns a pointer to the BDD of the subset if
+ successful. NULL if the procedure runs out of memory. The parameter
+ numVars is the maximum number of variables to be used in minterm
+ calculation and node count calculation. The optimal number should
+ be as close as possible to the size of the support of f. However,
+ it is safe to pass the value returned by Cudd_ReadSize for numVars
+ when the number of variables is under 1023. If numVars is larger
+ than 1023, it will overflow. If a 0 parameter is passed then the
+ procedure will compute a value which will avoid overflow but will
+ cause underflow with 2046 variables or more.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SubsetShortPaths Cudd_SupersetHeavyBranch Cudd_ReadSize]
+
+******************************************************************************/
+DdNode *
+Cudd_SubsetHeavyBranch(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be subset */,
+ int numVars /* number of variables in the support of f */,
+ int threshold /* maximum number of nodes in the subset */)
+{
+ DdNode *subset;
+
+ memOut = 0;
+ do {
+ dd->reordered = 0;
+ subset = cuddSubsetHeavyBranch(dd, f, numVars, threshold);
+ } while ((dd->reordered == 1) && (!memOut));
+
+ return(subset);
+
+} /* end of Cudd_SubsetHeavyBranch */
+
+
+/**Function********************************************************************
+
+ Synopsis [Extracts a dense superset from a BDD with the heavy branch
+ heuristic.]
+
+ Description [Extracts a dense superset from a BDD. The procedure is
+ identical to the subset procedure except for the fact that it
+ receives the complement of the given function. Extracting the subset
+ of the complement function is equivalent to extracting the superset
+ of the function. This procedure builds a superset by throwing away
+ one of the children of each node starting from the root of the
+ complement function, until the result is small enough. The child
+ that is eliminated from the result is the one that contributes the
+ fewer minterms.
+ Returns a pointer to the BDD of the superset if successful. NULL if
+ intermediate result causes the procedure to run out of memory. The
+ parameter numVars is the maximum number of variables to be used in
+ minterm calculation and node count calculation. The optimal number
+ should be as close as possible to the size of the support of f.
+ However, it is safe to pass the value returned by Cudd_ReadSize for
+ numVars when the number of variables is under 1023. If numVars is
+ larger than 1023, it will overflow. If a 0 parameter is passed then
+ the procedure will compute a value which will avoid overflow but
+ will cause underflow with 2046 variables or more.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SubsetHeavyBranch Cudd_SupersetShortPaths Cudd_ReadSize]
+
+******************************************************************************/
+DdNode *
+Cudd_SupersetHeavyBranch(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be superset */,
+ int numVars /* number of variables in the support of f */,
+ int threshold /* maximum number of nodes in the superset */)
+{
+ DdNode *subset, *g;
+
+ g = Cudd_Not(f);
+ memOut = 0;
+ do {
+ dd->reordered = 0;
+ subset = cuddSubsetHeavyBranch(dd, g, numVars, threshold);
+ } while ((dd->reordered == 1) && (!memOut));
+
+ return(Cudd_NotCond(subset, (subset != NULL)));
+
+} /* end of Cudd_SupersetHeavyBranch */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [The main procedure that returns a subset by choosing the heavier
+ branch in the BDD.]
+
+ Description [Here a subset BDD is built by throwing away one of the
+ children. Starting at root, annotate each node with the number of
+ minterms (in terms of the total number of variables specified -
+ numVars), number of nodes taken by the DAG rooted at this node and
+ number of additional nodes taken by the child that has the lesser
+ minterms. The child with the lower number of minterms is thrown away
+ and a dyanmic count of the nodes of the subset is kept. Once the
+ threshold is reached the subset is returned to the calling
+ procedure.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SubsetHeavyBranch]
+
+******************************************************************************/
+DdNode *
+cuddSubsetHeavyBranch(
+ DdManager * dd /* DD manager */,
+ DdNode * f /* current DD */,
+ int numVars /* maximum number of variables */,
+ int threshold /* threshold size for the subset */)
+{
+
+ int i, *size;
+ st_table *visitedTable;
+ int numNodes;
+ NodeData_t *currNodeQual;
+ DdNode *subset;
+ double minN;
+ st_table *storeTable, *approxTable;
+ char *key, *value;
+ st_generator *stGen;
+
+ if (f == NULL) {
+ fprintf(dd->err, "Cannot subset, nil object\n");
+ dd->errorCode = CUDD_INVALID_ARG;
+ return(NULL);
+ }
+
+ one = Cudd_ReadOne(dd);
+ zero = Cudd_Not(one);
+
+ /* If user does not know numVars value, set it to the maximum
+ * exponent that the pow function can take. The -1 is due to the
+ * discrepancy in the value that pow takes and the value that
+ * log gives.
+ */
+ if (numVars == 0) {
+ /* set default value */
+ numVars = DBL_MAX_EXP - 1;
+ }
+
+ if (Cudd_IsConstant(f)) {
+ return(f);
+ }
+
+ max = pow(2.0, (double)numVars);
+
+ /* Create visited table where structures for node data are allocated and
+ stored in a st_table */
+ visitedTable = SubsetCountMinterm(f, numVars);
+ if ((visitedTable == NULL) || memOut) {
+ (void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ numNodes = SubsetCountNodes(f, visitedTable, numVars);
+ if (memOut) {
+ (void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+
+ if (st_lookup(visitedTable, (char *)f, (char **)&currNodeQual)) {
+ minN = *(((NodeData_t *)currNodeQual)->mintermPointer);
+ } else {
+ fprintf(dd->err,
+ "Something is wrong, ought to be node quality table\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ }
+
+ size = ALLOC(int, 1);
+ if (size == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ *size = numNodes;
+
+#ifdef DEBUG
+ num_calls = 0;
+#endif
+ /* table to store nodes being created. */
+ storeTable = st_init_table(st_ptrcmp, st_ptrhash);
+ /* insert the constant */
+ cuddRef(one);
+ if (st_insert(storeTable, (char *)Cudd_ReadOne(dd), NIL(char)) ==
+ ST_OUT_OF_MEM) {
+ fprintf(dd->out, "Something wrong, st_table insert failed\n");
+ }
+ /* table to store approximations of nodes */
+ approxTable = st_init_table(st_ptrcmp, st_ptrhash);
+ subset = (DdNode *)BuildSubsetBdd(dd, f, size, visitedTable, threshold,
+ storeTable, approxTable);
+ if (subset != NULL) {
+ cuddRef(subset);
+ }
+
+ stGen = st_init_gen(approxTable);
+ if (stGen == NULL) {
+ st_free_table(approxTable);
+ return(NULL);
+ }
+ while(st_gen(stGen, (char **)&key, (char **)&value)) {
+ Cudd_RecursiveDeref(dd, (DdNode *)value);
+ }
+ st_free_gen(stGen); stGen = NULL;
+ st_free_table(approxTable);
+
+ stGen = st_init_gen(storeTable);
+ if (stGen == NULL) {
+ st_free_table(storeTable);
+ return(NULL);
+ }
+ while(st_gen(stGen, (char **)&key, (char **)&value)) {
+ Cudd_RecursiveDeref(dd, (DdNode *)key);
+ }
+ st_free_gen(stGen); stGen = NULL;
+ st_free_table(storeTable);
+
+ for (i = 0; i <= page; i++) {
+ FREE(mintermPages[i]);
+ }
+ FREE(mintermPages);
+ for (i = 0; i <= page; i++) {
+ FREE(nodePages[i]);
+ }
+ FREE(nodePages);
+ for (i = 0; i <= page; i++) {
+ FREE(lightNodePages[i]);
+ }
+ FREE(lightNodePages);
+ for (i = 0; i <= nodeDataPage; i++) {
+ FREE(nodeDataPages[i]);
+ }
+ FREE(nodeDataPages);
+ st_free_table(visitedTable);
+ FREE(size);
+#if 0
+ (void) Cudd_DebugCheck(dd);
+ (void) Cudd_CheckKeys(dd);
+#endif
+
+ if (subset != NULL) {
+#ifdef DD_DEBUG
+ if (!Cudd_bddLeq(dd, subset, f)) {
+ fprintf(dd->err, "Wrong subset\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+#endif
+ cuddDeref(subset);
+ return(subset);
+ } else {
+ return(NULL);
+ }
+} /* end of cuddSubsetHeavyBranch */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Resize the number of pages allocated to store the node data.]
+
+ Description [Resize the number of pages allocated to store the node data
+ The procedure moves the counter to the next page when the end of
+ the page is reached and allocates new pages when necessary.]
+
+ SideEffects [Changes the size of pages, page, page index, maximum
+ number of pages freeing stuff in case of memory out. ]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+ResizeNodeDataPages(
+ )
+{
+ int i;
+ NodeData_t **newNodeDataPages;
+
+ nodeDataPage++;
+ /* If the current page index is larger than the number of pages
+ * allocated, allocate a new page array. Page numbers are incremented by
+ * INITIAL_PAGES
+ */
+ if (nodeDataPage == maxNodeDataPages) {
+ newNodeDataPages = ALLOC(NodeData_t *,maxNodeDataPages + INITIAL_PAGES);
+ if (newNodeDataPages == NULL) {
+ for (i = 0; i < nodeDataPage; i++) FREE(nodeDataPages[i]);
+ FREE(nodeDataPages);
+ memOut = 1;
+ return;
+ } else {
+ for (i = 0; i < maxNodeDataPages; i++) {
+ newNodeDataPages[i] = nodeDataPages[i];
+ }
+ /* Increase total page count */
+ maxNodeDataPages += INITIAL_PAGES;
+ FREE(nodeDataPages);
+ nodeDataPages = newNodeDataPages;
+ }
+ }
+ /* Allocate a new page */
+ currentNodeDataPage = nodeDataPages[nodeDataPage] =
+ ALLOC(NodeData_t ,nodeDataPageSize);
+ if (currentNodeDataPage == NULL) {
+ for (i = 0; i < nodeDataPage; i++) FREE(nodeDataPages[i]);
+ FREE(nodeDataPages);
+ memOut = 1;
+ return;
+ }
+ /* reset page index */
+ nodeDataPageIndex = 0;
+ return;
+
+} /* end of ResizeNodeDataPages */
+
+
+/**Function********************************************************************
+
+ Synopsis [Resize the number of pages allocated to store the minterm
+ counts. ]
+
+ Description [Resize the number of pages allocated to store the minterm
+ counts. The procedure moves the counter to the next page when the
+ end of the page is reached and allocates new pages when necessary.]
+
+ SideEffects [Changes the size of minterm pages, page, page index, maximum
+ number of pages freeing stuff in case of memory out. ]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+ResizeCountMintermPages(
+ )
+{
+ int i;
+ double **newMintermPages;
+
+ page++;
+ /* If the current page index is larger than the number of pages
+ * allocated, allocate a new page array. Page numbers are incremented by
+ * INITIAL_PAGES
+ */
+ if (page == maxPages) {
+ newMintermPages = ALLOC(double *,maxPages + INITIAL_PAGES);
+ if (newMintermPages == NULL) {
+ for (i = 0; i < page; i++) FREE(mintermPages[i]);
+ FREE(mintermPages);
+ memOut = 1;
+ return;
+ } else {
+ for (i = 0; i < maxPages; i++) {
+ newMintermPages[i] = mintermPages[i];
+ }
+ /* Increase total page count */
+ maxPages += INITIAL_PAGES;
+ FREE(mintermPages);
+ mintermPages = newMintermPages;
+ }
+ }
+ /* Allocate a new page */
+ currentMintermPage = mintermPages[page] = ALLOC(double,pageSize);
+ if (currentMintermPage == NULL) {
+ for (i = 0; i < page; i++) FREE(mintermPages[i]);
+ FREE(mintermPages);
+ memOut = 1;
+ return;
+ }
+ /* reset page index */
+ pageIndex = 0;
+ return;
+
+} /* end of ResizeCountMintermPages */
+
+
+/**Function********************************************************************
+
+ Synopsis [Resize the number of pages allocated to store the node counts.]
+
+ Description [Resize the number of pages allocated to store the node counts.
+ The procedure moves the counter to the next page when the end of
+ the page is reached and allocates new pages when necessary.]
+
+ SideEffects [Changes the size of pages, page, page index, maximum
+ number of pages freeing stuff in case of memory out.]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+ResizeCountNodePages(
+ )
+{
+ int i;
+ int **newNodePages;
+
+ page++;
+
+ /* If the current page index is larger than the number of pages
+ * allocated, allocate a new page array. The number of pages is incremented
+ * by INITIAL_PAGES.
+ */
+ if (page == maxPages) {
+ newNodePages = ALLOC(int *,maxPages + INITIAL_PAGES);
+ if (newNodePages == NULL) {
+ for (i = 0; i < page; i++) FREE(nodePages[i]);
+ FREE(nodePages);
+ for (i = 0; i < page; i++) FREE(lightNodePages[i]);
+ FREE(lightNodePages);
+ memOut = 1;
+ return;
+ } else {
+ for (i = 0; i < maxPages; i++) {
+ newNodePages[i] = nodePages[i];
+ }
+ FREE(nodePages);
+ nodePages = newNodePages;
+ }
+
+ newNodePages = ALLOC(int *,maxPages + INITIAL_PAGES);
+ if (newNodePages == NULL) {
+ for (i = 0; i < page; i++) FREE(nodePages[i]);
+ FREE(nodePages);
+ for (i = 0; i < page; i++) FREE(lightNodePages[i]);
+ FREE(lightNodePages);
+ memOut = 1;
+ return;
+ } else {
+ for (i = 0; i < maxPages; i++) {
+ newNodePages[i] = lightNodePages[i];
+ }
+ FREE(lightNodePages);
+ lightNodePages = newNodePages;
+ }
+ /* Increase total page count */
+ maxPages += INITIAL_PAGES;
+ }
+ /* Allocate a new page */
+ currentNodePage = nodePages[page] = ALLOC(int,pageSize);
+ if (currentNodePage == NULL) {
+ for (i = 0; i < page; i++) FREE(nodePages[i]);
+ FREE(nodePages);
+ for (i = 0; i < page; i++) FREE(lightNodePages[i]);
+ FREE(lightNodePages);
+ memOut = 1;
+ return;
+ }
+ /* Allocate a new page */
+ currentLightNodePage = lightNodePages[page] = ALLOC(int,pageSize);
+ if (currentLightNodePage == NULL) {
+ for (i = 0; i <= page; i++) FREE(nodePages[i]);
+ FREE(nodePages);
+ for (i = 0; i < page; i++) FREE(lightNodePages[i]);
+ FREE(lightNodePages);
+ memOut = 1;
+ return;
+ }
+ /* reset page index */
+ pageIndex = 0;
+ return;
+
+} /* end of ResizeCountNodePages */
+
+
+/**Function********************************************************************
+
+ Synopsis [Recursively counts minterms of each node in the DAG.]
+
+ Description [Recursively counts minterms of each node in the DAG.
+ Similar to the cuddCountMintermAux which recursively counts the
+ number of minterms for the dag rooted at each node in terms of the
+ total number of variables (max). This procedure creates the node
+ data structure and stores the minterm count as part of the node
+ data structure. ]
+
+ SideEffects [Creates structures of type node quality and fills the st_table]
+
+ SeeAlso [SubsetCountMinterm]
+
+******************************************************************************/
+static double
+SubsetCountMintermAux(
+ DdNode * node /* function to analyze */,
+ double max /* number of minterms of constant 1 */,
+ st_table * table /* visitedTable table */)
+{
+
+ DdNode *N,*Nv,*Nnv; /* nodes to store cofactors */
+ double min,*pmin; /* minterm count */
+ double min1, min2; /* minterm count */
+ NodeData_t *dummy;
+ NodeData_t *newEntry;
+ int i;
+
+#ifdef DEBUG
+ num_calls++;
+#endif
+
+ /* Constant case */
+ if (Cudd_IsConstant(node)) {
+ if (node == zero) {
+ return(0.0);
+ } else {
+ return(max);
+ }
+ } else {
+
+ /* check if entry for this node exists */
+ if (st_lookup(table,(char *)node, (char **)&dummy)) {
+ min = *(dummy->mintermPointer);
+ return(min);
+ }
+
+ /* Make the node regular to extract cofactors */
+ N = Cudd_Regular(node);
+
+ /* store the cofactors */
+ Nv = Cudd_T(N);
+ Nnv = Cudd_E(N);
+
+ Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
+ Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));
+
+ min1 = SubsetCountMintermAux(Nv, max,table)/2.0;
+ if (memOut) return(0.0);
+ min2 = SubsetCountMintermAux(Nnv,max,table)/2.0;
+ if (memOut) return(0.0);
+ min = (min1+min2);
+
+ /* if page index is at the bottom, then create a new page */
+ if (pageIndex == pageSize) ResizeCountMintermPages();
+ if (memOut) {
+ for (i = 0; i <= nodeDataPage; i++) FREE(nodeDataPages[i]);
+ FREE(nodeDataPages);
+ st_free_table(table);
+ return(0.0);
+ }
+
+ /* point to the correct location in the page */
+ pmin = currentMintermPage+pageIndex;
+ pageIndex++;
+
+ /* store the minterm count of this node in the page */
+ *pmin = min;
+
+ /* Note I allocate the struct here. Freeing taken care of later */
+ if (nodeDataPageIndex == nodeDataPageSize) ResizeNodeDataPages();
+ if (memOut) {
+ for (i = 0; i <= page; i++) FREE(mintermPages[i]);
+ FREE(mintermPages);
+ st_free_table(table);
+ return(0.0);
+ }
+
+ newEntry = currentNodeDataPage + nodeDataPageIndex;
+ nodeDataPageIndex++;
+
+ /* points to the correct location in the page */
+ newEntry->mintermPointer = pmin;
+ /* initialize this field of the Node Quality structure */
+ newEntry->nodesPointer = NULL;
+
+ /* insert entry for the node in the table */
+ if (st_insert(table,(char *)node, (char *)newEntry) == ST_OUT_OF_MEM) {
+ memOut = 1;
+ for (i = 0; i <= page; i++) FREE(mintermPages[i]);
+ FREE(mintermPages);
+ for (i = 0; i <= nodeDataPage; i++) FREE(nodeDataPages[i]);
+ FREE(nodeDataPages);
+ st_free_table(table);
+ return(0.0);
+ }
+ return(min);
+ }
+
+} /* end of SubsetCountMintermAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts minterms of each node in the DAG]
+
+ Description [Counts minterms of each node in the DAG. Similar to the
+ Cudd_CountMinterm procedure except this returns the minterm count for
+ all the nodes in the bdd in an st_table.]
+
+ SideEffects [none]
+
+ SeeAlso [SubsetCountMintermAux]
+
+******************************************************************************/
+static st_table *
+SubsetCountMinterm(
+ DdNode * node /* function to be analyzed */,
+ int nvars /* number of variables node depends on */)
+{
+ st_table *table;
+ double num;
+ int i;
+
+
+#ifdef DEBUG
+ num_calls = 0;
+#endif
+
+ max = pow(2.0,(double) nvars);
+ table = st_init_table(st_ptrcmp,st_ptrhash);
+ if (table == NULL) goto OUT_OF_MEM;
+ maxPages = INITIAL_PAGES;
+ mintermPages = ALLOC(double *,maxPages);
+ if (mintermPages == NULL) {
+ st_free_table(table);
+ goto OUT_OF_MEM;
+ }
+ page = 0;
+ currentMintermPage = ALLOC(double,pageSize);
+ mintermPages[page] = currentMintermPage;
+ if (currentMintermPage == NULL) {
+ FREE(mintermPages);
+ st_free_table(table);
+ goto OUT_OF_MEM;
+ }
+ pageIndex = 0;
+ maxNodeDataPages = INITIAL_PAGES;
+ nodeDataPages = ALLOC(NodeData_t *, maxNodeDataPages);
+ if (nodeDataPages == NULL) {
+ for (i = 0; i <= page ; i++) FREE(mintermPages[i]);
+ FREE(mintermPages);
+ st_free_table(table);
+ goto OUT_OF_MEM;
+ }
+ nodeDataPage = 0;
+ currentNodeDataPage = ALLOC(NodeData_t ,nodeDataPageSize);
+ nodeDataPages[nodeDataPage] = currentNodeDataPage;
+ if (currentNodeDataPage == NULL) {
+ for (i = 0; i <= page ; i++) FREE(mintermPages[i]);
+ FREE(mintermPages);
+ FREE(nodeDataPages);
+ st_free_table(table);
+ goto OUT_OF_MEM;
+ }
+ nodeDataPageIndex = 0;
+
+ num = SubsetCountMintermAux(node,max,table);
+ if (memOut) goto OUT_OF_MEM;
+ return(table);
+
+OUT_OF_MEM:
+ memOut = 1;
+ return(NULL);
+
+} /* end of SubsetCountMinterm */
+
+
+/**Function********************************************************************
+
+ Synopsis [Recursively counts the number of nodes under the dag.
+ Also counts the number of nodes under the lighter child of
+ this node.]
+
+ Description [Recursively counts the number of nodes under the dag.
+ Also counts the number of nodes under the lighter child of
+ this node. . Note that the same dag may be the lighter child of two
+ different nodes and have different counts. As with the minterm counts,
+ the node counts are stored in pages to be space efficient and the
+ address for these node counts are stored in an st_table associated
+ to each node. ]
+
+ SideEffects [Updates the node data table with node counts]
+
+ SeeAlso [SubsetCountNodes]
+
+******************************************************************************/
+static int
+SubsetCountNodesAux(
+ DdNode * node /* current node */,
+ st_table * table /* table to update node count, also serves as visited table. */,
+ double max /* maximum number of variables */)
+{
+ int tval, eval, i;
+ DdNode *N, *Nv, *Nnv;
+ double minNv, minNnv;
+ NodeData_t *dummyN, *dummyNv, *dummyNnv, *dummyNBar;
+ int *pmin, *pminBar, *val;
+
+ if ((node == NULL) || Cudd_IsConstant(node))
+ return(0);
+
+ /* if this node has been processed do nothing */
+ if (st_lookup(table, (char *)node, (char **)&dummyN) == 1) {
+ val = dummyN->nodesPointer;
+ if (val != NULL)
+ return(0);
+ } else {
+ return(0);
+ }
+
+ N = Cudd_Regular(node);
+ Nv = Cudd_T(N);
+ Nnv = Cudd_E(N);
+
+ Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
+ Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));
+
+ /* find the minterm counts for the THEN and ELSE branches */
+ if (Cudd_IsConstant(Nv)) {
+ if (Nv == zero) {
+ minNv = 0.0;
+ } else {
+ minNv = max;
+ }
+ } else {
+ if (st_lookup(table, (char *)Nv, (char **)&dummyNv) == 1)
+ minNv = *(dummyNv->mintermPointer);
+ else {
+ return(0);
+ }
+ }
+ if (Cudd_IsConstant(Nnv)) {
+ if (Nnv == zero) {
+ minNnv = 0.0;
+ } else {
+ minNnv = max;
+ }
+ } else {
+ if (st_lookup(table, (char *)Nnv, (char **)&dummyNnv) == 1) {
+ minNnv = *(dummyNnv->mintermPointer);
+ }
+ else {
+ return(0);
+ }
+ }
+
+
+ /* recur based on which has larger minterm, */
+ if (minNv >= minNnv) {
+ tval = SubsetCountNodesAux(Nv, table, max);
+ if (memOut) return(0);
+ eval = SubsetCountNodesAux(Nnv, table, max);
+ if (memOut) return(0);
+
+ /* store the node count of the lighter child. */
+ if (pageIndex == pageSize) ResizeCountNodePages();
+ if (memOut) {
+ for (i = 0; i <= page; i++) FREE(mintermPages[i]);
+ FREE(mintermPages);
+ for (i = 0; i <= nodeDataPage; i++) FREE(nodeDataPages[i]);
+ FREE(nodeDataPages);
+ st_free_table(table);
+ return(0);
+ }
+ pmin = currentLightNodePage + pageIndex;
+ *pmin = eval; /* Here the ELSE child is lighter */
+ dummyN->lightChildNodesPointer = pmin;
+
+ } else {
+ eval = SubsetCountNodesAux(Nnv, table, max);
+ if (memOut) return(0);
+ tval = SubsetCountNodesAux(Nv, table, max);
+ if (memOut) return(0);
+
+ /* store the node count of the lighter child. */
+ if (pageIndex == pageSize) ResizeCountNodePages();
+ if (memOut) {
+ for (i = 0; i <= page; i++) FREE(mintermPages[i]);
+ FREE(mintermPages);
+ for (i = 0; i <= nodeDataPage; i++) FREE(nodeDataPages[i]);
+ FREE(nodeDataPages);
+ st_free_table(table);
+ return(0);
+ }
+ pmin = currentLightNodePage + pageIndex;
+ *pmin = tval; /* Here the THEN child is lighter */
+ dummyN->lightChildNodesPointer = pmin;
+
+ }
+ /* updating the page index for node count storage. */
+ pmin = currentNodePage + pageIndex;
+ *pmin = tval + eval + 1;
+ dummyN->nodesPointer = pmin;
+
+ /* pageIndex is parallel page index for count_nodes and count_lightNodes */
+ pageIndex++;
+
+ /* if this node has been reached first, it belongs to a heavier
+ branch. Its complement will be reached later on a lighter branch.
+ Hence the complement has zero node count. */
+
+ if (st_lookup(table, (char *)Cudd_Not(node), (char **)&dummyNBar) == 1) {
+ if (pageIndex == pageSize) ResizeCountNodePages();
+ if (memOut) {
+ for (i = 0; i < page; i++) FREE(mintermPages[i]);
+ FREE(mintermPages);
+ for (i = 0; i < nodeDataPage; i++) FREE(nodeDataPages[i]);
+ FREE(nodeDataPages);
+ st_free_table(table);
+ return(0);
+ }
+ pminBar = currentLightNodePage + pageIndex;
+ *pminBar = 0;
+ dummyNBar->lightChildNodesPointer = pminBar;
+ /* The lighter child has less nodes than the parent.
+ * So if parent 0 then lighter child zero
+ */
+ if (pageIndex == pageSize) ResizeCountNodePages();
+ if (memOut) {
+ for (i = 0; i < page; i++) FREE(mintermPages[i]);
+ FREE(mintermPages);
+ for (i = 0; i < nodeDataPage; i++) FREE(nodeDataPages[i]);
+ FREE(nodeDataPages);
+ st_free_table(table);
+ return(0);
+ }
+ pminBar = currentNodePage + pageIndex;
+ *pminBar = 0;
+ dummyNBar->nodesPointer = pminBar ; /* maybe should point to zero */
+
+ pageIndex++;
+ }
+ return(*pmin);
+} /*end of SubsetCountNodesAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the nodes under the current node and its lighter child]
+
+ Description [Counts the nodes under the current node and its lighter
+ child. Calls a recursive procedure to count the number of nodes of
+ a DAG rooted at a particular node and the number of nodes taken by its
+ lighter child.]
+
+ SideEffects [None]
+
+ SeeAlso [SubsetCountNodesAux]
+
+******************************************************************************/
+static int
+SubsetCountNodes(
+ DdNode * node /* function to be analyzed */,
+ st_table * table /* node quality table */,
+ int nvars /* number of variables node depends on */)
+{
+ int num;
+ int i;
+
+#ifdef DEBUG
+ num_calls = 0;
+#endif
+
+ max = pow(2.0,(double) nvars);
+ maxPages = INITIAL_PAGES;
+ nodePages = ALLOC(int *,maxPages);
+ if (nodePages == NULL) {
+ goto OUT_OF_MEM;
+ }
+
+ lightNodePages = ALLOC(int *,maxPages);
+ if (lightNodePages == NULL) {
+ for (i = 0; i <= page; i++) FREE(mintermPages[i]);
+ FREE(mintermPages);
+ for (i = 0; i <= nodeDataPage; i++) FREE(nodeDataPages[i]);
+ FREE(nodeDataPages);
+ FREE(nodePages);
+ goto OUT_OF_MEM;
+ }
+
+ page = 0;
+ currentNodePage = nodePages[page] = ALLOC(int,pageSize);
+ if (currentNodePage == NULL) {
+ for (i = 0; i <= page; i++) FREE(mintermPages[i]);
+ FREE(mintermPages);
+ for (i = 0; i <= nodeDataPage; i++) FREE(nodeDataPages[i]);
+ FREE(nodeDataPages);
+ FREE(lightNodePages);
+ FREE(nodePages);
+ goto OUT_OF_MEM;
+ }
+
+ currentLightNodePage = lightNodePages[page] = ALLOC(int,pageSize);
+ if (currentLightNodePage == NULL) {
+ for (i = 0; i <= page; i++) FREE(mintermPages[i]);
+ FREE(mintermPages);
+ for (i = 0; i <= nodeDataPage; i++) FREE(nodeDataPages[i]);
+ FREE(nodeDataPages);
+ FREE(currentNodePage);
+ FREE(lightNodePages);
+ FREE(nodePages);
+ goto OUT_OF_MEM;
+ }
+
+ pageIndex = 0;
+ num = SubsetCountNodesAux(node,table,max);
+ if (memOut) goto OUT_OF_MEM;
+ return(num);
+
+OUT_OF_MEM:
+ memOut = 1;
+ return(0);
+
+} /* end of SubsetCountNodes */
+
+
+/**Function********************************************************************
+
+ Synopsis [Procedure to recursively store nodes that are retained in the subset.]
+
+ Description [rocedure to recursively store nodes that are retained in the subset.]
+
+ SideEffects [None]
+
+ SeeAlso [StoreNodes]
+
+******************************************************************************/
+static void
+StoreNodes(
+ st_table * storeTable,
+ DdManager * dd,
+ DdNode * node)
+{
+ char *dummy;
+ DdNode *N, *Nt, *Ne;
+ if (Cudd_IsConstant(dd)) {
+ return;
+ }
+ N = Cudd_Regular(node);
+ if (st_lookup(storeTable, (char *)N, (char **)&dummy)) {
+ return;
+ }
+ cuddRef(N);
+ if (st_insert(storeTable, (char *)N, NIL(char)) == ST_OUT_OF_MEM) {
+ fprintf(dd->err,"Something wrong, st_table insert failed\n");
+ }
+
+ Nt = Cudd_T(N);
+ Ne = Cudd_E(N);
+
+ StoreNodes(storeTable, dd, Nt);
+ StoreNodes(storeTable, dd, Ne);
+ return;
+
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Builds the subset BDD using the heavy branch method.]
+
+ Description [The procedure carries out the building of the subset BDD
+ starting at the root. Using the three different counts labelling each node,
+ the procedure chooses the heavier branch starting from the root and keeps
+ track of the number of nodes it discards at each step, thus keeping count
+ of the size of the subset BDD dynamically. Once the threshold is satisfied,
+ the procedure then calls ITE to build the BDD.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+BuildSubsetBdd(
+ DdManager * dd /* DD manager */,
+ DdNode * node /* current node */,
+ int * size /* current size of the subset */,
+ st_table * visitedTable /* visited table storing all node data */,
+ int threshold,
+ st_table * storeTable,
+ st_table * approxTable)
+{
+
+ DdNode *Nv, *Nnv, *N, *topv, *neW;
+ double minNv, minNnv;
+ NodeData_t *currNodeQual;
+ NodeData_t *currNodeQualT;
+ NodeData_t *currNodeQualE;
+ DdNode *ThenBranch, *ElseBranch;
+ unsigned int topid;
+ char *dummy;
+
+#ifdef DEBUG
+ num_calls++;
+#endif
+ /*If the size of the subset is below the threshold, dont do
+ anything. */
+ if ((*size) <= threshold) {
+ /* store nodes below this, so we can recombine if possible */
+ StoreNodes(storeTable, dd, node);
+ return(node);
+ }
+
+ if (Cudd_IsConstant(node))
+ return(node);
+
+ /* Look up minterm count for this node. */
+ if (!st_lookup(visitedTable, (char *)node, (char **)&currNodeQual)) {
+ fprintf(dd->err,
+ "Something is wrong, ought to be in node quality table\n");
+ }
+
+ /* Get children. */
+ N = Cudd_Regular(node);
+ Nv = Cudd_T(N);
+ Nnv = Cudd_E(N);
+
+ /* complement if necessary */
+ Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
+ Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));
+
+ if (!Cudd_IsConstant(Nv)) {
+ /* find out minterms and nodes contributed by then child */
+ if (!st_lookup(visitedTable, (char *)Nv,
+ (char **)&currNodeQualT)) {
+ fprintf(dd->out,"Something wrong, couldnt find nodes in node quality table\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+ else {
+ minNv = *(((NodeData_t *)currNodeQualT)->mintermPointer);
+ }
+ } else {
+ if (Nv == zero) {
+ minNv = 0;
+ } else {
+ minNv = max;
+ }
+ }
+ if (!Cudd_IsConstant(Nnv)) {
+ /* find out minterms and nodes contributed by else child */
+ if (!st_lookup(visitedTable, (char *)Nnv, (char **)&currNodeQualE)) {
+ fprintf(dd->out,"Something wrong, couldnt find nodes in node quality table\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ } else {
+ minNnv = *(((NodeData_t *)currNodeQualE)->mintermPointer);
+ }
+ } else {
+ if (Nnv == zero) {
+ minNnv = 0;
+ } else {
+ minNnv = max;
+ }
+ }
+
+ /* keep track of size of subset by subtracting the number of
+ * differential nodes contributed by lighter child
+ */
+ *size = (*(size)) - (int)*(currNodeQual->lightChildNodesPointer);
+ if (minNv >= minNnv) { /*SubsetCountNodesAux procedure takes
+ the Then branch in case of a tie */
+
+ /* recur with the Then branch */
+ ThenBranch = (DdNode *)BuildSubsetBdd(dd, Nv, size,
+ visitedTable, threshold, storeTable, approxTable);
+ if (ThenBranch == NULL) {
+ return(NULL);
+ }
+ cuddRef(ThenBranch);
+ /* The Else branch is either a node that already exists in the
+ * subset, or one whose approximation has been computed, or
+ * Zero.
+ */
+ if (st_lookup(storeTable, (char *)Cudd_Regular(Nnv), (char **)&dummy)) {
+ ElseBranch = Nnv;
+ cuddRef(ElseBranch);
+ } else {
+ if (st_lookup(approxTable, (char *)Nnv, (char **)&dummy)) {
+ ElseBranch = (DdNode *)dummy;
+ cuddRef(ElseBranch);
+ } else {
+ ElseBranch = zero;
+ cuddRef(ElseBranch);
+ }
+ }
+
+ }
+ else {
+ /* recur with the Else branch */
+ ElseBranch = (DdNode *)BuildSubsetBdd(dd, Nnv, size,
+ visitedTable, threshold, storeTable, approxTable);
+ if (ElseBranch == NULL) {
+ return(NULL);
+ }
+ cuddRef(ElseBranch);
+ /* The Then branch is either a node that already exists in the
+ * subset, or one whose approximation has been computed, or
+ * Zero.
+ */
+ if (st_lookup(storeTable, (char *)Cudd_Regular(Nv), (char **)&dummy)) {
+ ThenBranch = Nv;
+ cuddRef(ThenBranch);
+ } else {
+ if (st_lookup(approxTable, (char *)Nv, (char **)&dummy)) {
+ ThenBranch = (DdNode *)dummy;
+ cuddRef(ThenBranch);
+ } else {
+ ThenBranch = zero;
+ cuddRef(ThenBranch);
+ }
+ }
+ }
+
+ /* construct the Bdd with the top variable and the two children */
+ topid = Cudd_NodeReadIndex(N);
+ topv = Cudd_ReadVars(dd, topid);
+ cuddRef(topv);
+ neW = cuddBddIteRecur(dd, topv, ThenBranch, ElseBranch);
+ if (neW != NULL) {
+ cuddRef(neW);
+ }
+ Cudd_RecursiveDeref(dd, topv);
+ Cudd_RecursiveDeref(dd, ThenBranch);
+ Cudd_RecursiveDeref(dd, ElseBranch);
+
+
+ if (neW == NULL)
+ return(NULL);
+ else {
+ /* store this node in the store table */
+ if (!st_lookup(storeTable, (char *)Cudd_Regular(neW), (char **)&dummy)) {
+ cuddRef(neW);
+ st_insert(storeTable, (char *)Cudd_Regular(neW), (char *)NIL(char));
+
+ }
+ /* store the approximation for this node */
+ if (N != Cudd_Regular(neW)) {
+ if (st_lookup(approxTable, (char *)node, (char **)&dummy)) {
+ fprintf(dd->err, "This node should not be in the approximated table\n");
+ } else {
+ cuddRef(neW);
+ st_insert(approxTable, (char *)node, (char *)neW);
+ }
+ }
+ cuddDeref(neW);
+ return(neW);
+ }
+} /* end of BuildSubsetBdd */
+
diff --git a/src/bdd/cudd/cuddSubsetSP.c b/src/bdd/cudd/cuddSubsetSP.c
new file mode 100644
index 00000000..0f7209dd
--- /dev/null
+++ b/src/bdd/cudd/cuddSubsetSP.c
@@ -0,0 +1,1624 @@
+/**CFile***********************************************************************
+
+ FileName [cuddSubsetSP.c]
+
+ PackageName [cudd]
+
+ Synopsis [Procedure to subset the given BDD choosing the shortest paths
+ (largest cubes) in the BDD.]
+
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_SubsetShortPaths()
+ <li> Cudd_SupersetShortPaths()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddSubsetShortPaths()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> BuildSubsetBdd()
+ <li> CreatePathTable()
+ <li> AssessPathLength()
+ <li> CreateTopDist()
+ <li> CreateBotDist()
+ <li> ResizeNodeDistPages()
+ <li> ResizeQueuePages()
+ <li> stPathTableDdFree()
+ </ul>
+ ]
+
+ SeeAlso [cuddSubsetHB.c]
+
+ Author [Kavita Ravi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define DEFAULT_PAGE_SIZE 2048 /* page size to store the BFS queue element type */
+#define DEFAULT_NODE_DIST_PAGE_SIZE 2048 /* page sizesto store NodeDist_t type */
+#define MAXSHORTINT ((DdHalfWord) ~0) /* constant defined to store
+ * maximum distance of a node
+ * from the root or the
+ * constant
+ */
+#define INITIAL_PAGES 128 /* number of initial pages for the
+ * queue/NodeDist_t type */
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/* structure created to store subset results for each node and distances with
+ * odd and even parity of the node from the root and sink. Main data structure
+ * in this procedure.
+ */
+struct NodeDist{
+ DdHalfWord oddTopDist;
+ DdHalfWord evenTopDist;
+ DdHalfWord oddBotDist;
+ DdHalfWord evenBotDist;
+ DdNode *regResult;
+ DdNode *compResult;
+};
+
+/* assorted information needed by the BuildSubsetBdd procedure. */
+struct AssortedInfo {
+ unsigned int maxpath;
+ int findShortestPath;
+ int thresholdReached;
+ st_table *maxpathTable;
+ int threshold;
+};
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+typedef struct NodeDist NodeDist_t;
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddSubsetSP.c,v 1.1.1.1 2003/02/24 22:23:53 wjiang Exp $";
+#endif
+
+#ifdef DD_DEBUG
+static int numCalls;
+static int hits;
+static int thishit;
+#endif
+
+
+static int memOut; /* flag to indicate out of memory */
+static DdNode *zero, *one; /* constant functions */
+
+static NodeDist_t **nodeDistPages; /* pointers to the pages */
+static int nodeDistPageIndex; /* index to next element */
+static int nodeDistPage; /* index to current page */
+static int nodeDistPageSize = DEFAULT_NODE_DIST_PAGE_SIZE; /* page size */
+static int maxNodeDistPages; /* number of page pointers */
+static NodeDist_t *currentNodeDistPage; /* current page */
+
+static DdNode ***queuePages; /* pointers to the pages */
+static int queuePageIndex; /* index to next element */
+static int queuePage; /* index to current page */
+static int queuePageSize = DEFAULT_PAGE_SIZE; /* page size */
+static int maxQueuePages; /* number of page pointers */
+static DdNode **currentQueuePage; /* current page */
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static void ResizeNodeDistPages ARGS(());
+static void ResizeQueuePages ARGS(());
+static void CreateTopDist ARGS((st_table *pathTable, int parentPage, int parentQueueIndex, int topLen, DdNode **childPage, int childQueueIndex, int numParents, FILE *fp));
+static int CreateBotDist ARGS((DdNode *node, st_table *pathTable, unsigned int *pathLengthArray, FILE *fp));
+static st_table * CreatePathTable ARGS((DdNode *node, unsigned int *pathLengthArray, FILE *fp));
+static unsigned int AssessPathLength ARGS((unsigned int *pathLengthArray, int threshold, int numVars, unsigned int *excess, FILE *fp));
+static DdNode * BuildSubsetBdd ARGS((DdManager *dd, st_table *pathTable, DdNode *node, struct AssortedInfo *info, st_table *subsetNodeTable));
+static enum st_retval stPathTableDdFree ARGS((char *key, char *value, char *arg));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of Exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Extracts a dense subset from a BDD with the shortest paths
+ heuristic.]
+
+ Description [Extracts a dense subset from a BDD. This procedure
+ tries to preserve the shortest paths of the input BDD, because they
+ give many minterms and contribute few nodes. This procedure may
+ increase the number of nodes in trying to create the subset or
+ reduce the number of nodes due to recombination as compared to the
+ original BDD. Hence the threshold may not be strictly adhered to. In
+ practice, recombination overshadows the increase in the number of
+ nodes and results in small BDDs as compared to the threshold. The
+ hardlimit specifies whether threshold needs to be strictly adhered
+ to. If it is set to 1, the procedure ensures that result is never
+ larger than the specified limit but may be considerably less than
+ the threshold. Returns a pointer to the BDD for the subset if
+ successful; NULL otherwise. The value for numVars should be as
+ close as possible to the size of the support of f for better
+ efficiency. However, it is safe to pass the value returned by
+ Cudd_ReadSize for numVars. If 0 is passed, then the value returned
+ by Cudd_ReadSize is used.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SupersetShortPaths Cudd_SubsetHeavyBranch Cudd_ReadSize]
+
+******************************************************************************/
+DdNode *
+Cudd_SubsetShortPaths(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be subset */,
+ int numVars /* number of variables in the support of f */,
+ int threshold /* maximum number of nodes in the subset */,
+ int hardlimit /* flag: 1 if threshold is a hard limit */)
+{
+ DdNode *subset;
+
+ memOut = 0;
+ do {
+ dd->reordered = 0;
+ subset = cuddSubsetShortPaths(dd, f, numVars, threshold, hardlimit);
+ } while((dd->reordered ==1) && (!memOut));
+
+ return(subset);
+
+} /* end of Cudd_SubsetShortPaths */
+
+
+/**Function********************************************************************
+
+ Synopsis [Extracts a dense superset from a BDD with the shortest paths
+ heuristic.]
+
+ Description [Extracts a dense superset from a BDD. The procedure is
+ identical to the subset procedure except for the fact that it
+ receives the complement of the given function. Extracting the subset
+ of the complement function is equivalent to extracting the superset
+ of the function. This procedure tries to preserve the shortest
+ paths of the complement BDD, because they give many minterms and
+ contribute few nodes. This procedure may increase the number of
+ nodes in trying to create the superset or reduce the number of nodes
+ due to recombination as compared to the original BDD. Hence the
+ threshold may not be strictly adhered to. In practice, recombination
+ overshadows the increase in the number of nodes and results in small
+ BDDs as compared to the threshold. The hardlimit specifies whether
+ threshold needs to be strictly adhered to. If it is set to 1, the
+ procedure ensures that result is never larger than the specified
+ limit but may be considerably less than the threshold. Returns a
+ pointer to the BDD for the superset if successful; NULL
+ otherwise. The value for numVars should be as close as possible to
+ the size of the support of f for better efficiency. However, it is
+ safe to pass the value returned by Cudd_ReadSize for numVar. If 0
+ is passed, then the value returned by Cudd_ReadSize is used.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SubsetShortPaths Cudd_SupersetHeavyBranch Cudd_ReadSize]
+
+******************************************************************************/
+DdNode *
+Cudd_SupersetShortPaths(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be superset */,
+ int numVars /* number of variables in the support of f */,
+ int threshold /* maximum number of nodes in the subset */,
+ int hardlimit /* flag: 1 if threshold is a hard limit */)
+{
+ DdNode *subset, *g;
+
+ g = Cudd_Not(f);
+ memOut = 0;
+ do {
+ dd->reordered = 0;
+ subset = cuddSubsetShortPaths(dd, g, numVars, threshold, hardlimit);
+ } while((dd->reordered ==1) && (!memOut));
+
+ return(Cudd_NotCond(subset, (subset != NULL)));
+
+} /* end of Cudd_SupersetShortPaths */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [The outermost procedure to return a subset of the given BDD
+ with the shortest path lengths.]
+
+ Description [The outermost procedure to return a subset of the given
+ BDD with the largest cubes. The path lengths are calculated, the maximum
+ allowable path length is determined and the number of nodes of this
+ path length that can be used to build a subset. If the threshold is
+ larger than the size of the original BDD, the original BDD is
+ returned. ]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SubsetShortPaths]
+
+******************************************************************************/
+DdNode *
+cuddSubsetShortPaths(
+ DdManager * dd /* DD manager */,
+ DdNode * f /* function to be subset */,
+ int numVars /* total number of variables in consideration */,
+ int threshold /* maximum number of nodes allowed in the subset */,
+ int hardlimit /* flag determining whether thershold should be respected strictly */)
+{
+ st_table *pathTable;
+ DdNode *N, *subset;
+
+ unsigned int *pathLengthArray;
+ unsigned int maxpath, oddLen, evenLen, pathLength, *excess;
+ int i;
+ NodeDist_t *nodeStat;
+ struct AssortedInfo *info;
+ st_table *subsetNodeTable;
+
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+
+ if (numVars == 0) {
+ /* set default value */
+ numVars = Cudd_ReadSize(dd);
+ }
+
+ if (threshold > numVars) {
+ threshold = threshold - numVars;
+ }
+ if (f == NULL) {
+ fprintf(dd->err, "Cannot partition, nil object\n");
+ dd->errorCode = CUDD_INVALID_ARG;
+ return(NULL);
+ }
+ if (Cudd_IsConstant(f))
+ return (f);
+
+ pathLengthArray = ALLOC(unsigned int, numVars+1);
+ for (i = 0; i < numVars+1; i++) pathLengthArray[i] = 0;
+
+
+#ifdef DD_DEBUG
+ numCalls = 0;
+#endif
+
+ pathTable = CreatePathTable(f, pathLengthArray, dd->err);
+
+ if ((pathTable == NULL) || (memOut)) {
+ if (pathTable != NULL)
+ st_free_table(pathTable);
+ FREE(pathLengthArray);
+ return (NIL(DdNode));
+ }
+
+ excess = ALLOC(unsigned int, 1);
+ *excess = 0;
+ maxpath = AssessPathLength(pathLengthArray, threshold, numVars, excess,
+ dd->err);
+
+ if (maxpath != (unsigned) (numVars + 1)) {
+
+ info = ALLOC(struct AssortedInfo, 1);
+ info->maxpath = maxpath;
+ info->findShortestPath = 0;
+ info->thresholdReached = *excess;
+ info->maxpathTable = st_init_table(st_ptrcmp, st_ptrhash);
+ info->threshold = threshold;
+
+#ifdef DD_DEBUG
+ (void) fprintf(dd->out, "Path length array\n");
+ for (i = 0; i < (numVars+1); i++) {
+ if (pathLengthArray[i])
+ (void) fprintf(dd->out, "%d ",i);
+ }
+ (void) fprintf(dd->out, "\n");
+ for (i = 0; i < (numVars+1); i++) {
+ if (pathLengthArray[i])
+ (void) fprintf(dd->out, "%d ",pathLengthArray[i]);
+ }
+ (void) fprintf(dd->out, "\n");
+ (void) fprintf(dd->out, "Maxpath = %d, Thresholdreached = %d\n",
+ maxpath, info->thresholdReached);
+#endif
+
+ N = Cudd_Regular(f);
+ if (!st_lookup(pathTable, (char *)N, (char **)&nodeStat)) {
+ fprintf(dd->err, "Something wrong, root node must be in table\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ } else {
+ if ((nodeStat->oddTopDist != MAXSHORTINT) &&
+ (nodeStat->oddBotDist != MAXSHORTINT))
+ oddLen = (nodeStat->oddTopDist + nodeStat->oddBotDist);
+ else
+ oddLen = MAXSHORTINT;
+
+ if ((nodeStat->evenTopDist != MAXSHORTINT) &&
+ (nodeStat->evenBotDist != MAXSHORTINT))
+ evenLen = (nodeStat->evenTopDist +nodeStat->evenBotDist);
+ else
+ evenLen = MAXSHORTINT;
+
+ pathLength = (oddLen <= evenLen) ? oddLen : evenLen;
+ if (pathLength > maxpath) {
+ (void) fprintf(dd->err, "All computations are bogus, since root has path length greater than max path length within threshold %d, %d\n", maxpath, pathLength);
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+ }
+
+#ifdef DD_DEBUG
+ numCalls = 0;
+ hits = 0;
+ thishit = 0;
+#endif
+ /* initialize a table to store computed nodes */
+ if (hardlimit) {
+ subsetNodeTable = st_init_table(st_ptrcmp, st_ptrhash);
+ } else {
+ subsetNodeTable = NIL(st_table);
+ }
+ subset = BuildSubsetBdd(dd, pathTable, f, info, subsetNodeTable);
+ if (subset != NULL) {
+ cuddRef(subset);
+ }
+ /* record the number of times a computed result for a node is hit */
+
+#ifdef DD_DEBUG
+ (void) fprintf(dd->out, "Hits = %d, New==Node = %d, NumCalls = %d\n",
+ hits, thishit, numCalls);
+#endif
+
+ if (subsetNodeTable != NIL(st_table)) {
+ st_free_table(subsetNodeTable);
+ }
+ st_free_table(info->maxpathTable);
+ st_foreach(pathTable, stPathTableDdFree, (char *)dd);
+
+ FREE(info);
+
+ } else {/* if threshold larger than size of dd */
+ subset = f;
+ cuddRef(subset);
+ }
+ FREE(excess);
+ st_free_table(pathTable);
+ FREE(pathLengthArray);
+ for (i = 0; i <= nodeDistPage; i++) FREE(nodeDistPages[i]);
+ FREE(nodeDistPages);
+
+#ifdef DD_DEBUG
+ /* check containment of subset in f */
+ if (subset != NULL) {
+ DdNode *check;
+ check = Cudd_bddIteConstant(dd, subset, f, one);
+ if (check != one) {
+ (void) fprintf(dd->err, "Wrong partition\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+ }
+#endif
+
+ if (subset != NULL) {
+ cuddDeref(subset);
+ return(subset);
+ } else {
+ return(NULL);
+ }
+
+} /* end of cuddSubsetShortPaths */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Resize the number of pages allocated to store the distances
+ related to each node.]
+
+ Description [Resize the number of pages allocated to store the distances
+ related to each node. The procedure moves the counter to the
+ next page when the end of the page is reached and allocates new
+ pages when necessary. ]
+
+ SideEffects [Changes the size of pages, page, page index, maximum
+ number of pages freeing stuff in case of memory out. ]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+ResizeNodeDistPages(
+ )
+{
+ int i;
+ NodeDist_t **newNodeDistPages;
+
+ /* move to next page */
+ nodeDistPage++;
+
+ /* If the current page index is larger than the number of pages
+ * allocated, allocate a new page array. Page numbers are incremented by
+ * INITIAL_PAGES
+ */
+ if (nodeDistPage == maxNodeDistPages) {
+ newNodeDistPages = ALLOC(NodeDist_t *,maxNodeDistPages + INITIAL_PAGES);
+ if (newNodeDistPages == NULL) {
+ for (i = 0; i < nodeDistPage; i++) FREE(nodeDistPages[i]);
+ FREE(nodeDistPages);
+ memOut = 1;
+ return;
+ } else {
+ for (i = 0; i < maxNodeDistPages; i++) {
+ newNodeDistPages[i] = nodeDistPages[i];
+ }
+ /* Increase total page count */
+ maxNodeDistPages += INITIAL_PAGES;
+ FREE(nodeDistPages);
+ nodeDistPages = newNodeDistPages;
+ }
+ }
+ /* Allocate a new page */
+ currentNodeDistPage = nodeDistPages[nodeDistPage] = ALLOC(NodeDist_t,
+ nodeDistPageSize);
+ if (currentNodeDistPage == NULL) {
+ for (i = 0; i < nodeDistPage; i++) FREE(nodeDistPages[i]);
+ FREE(nodeDistPages);
+ memOut = 1;
+ return;
+ }
+ /* reset page index */
+ nodeDistPageIndex = 0;
+ return;
+
+} /* end of ResizeNodeDistPages */
+
+
+/**Function********************************************************************
+
+ Synopsis [Resize the number of pages allocated to store nodes in the BFS
+ traversal of the Bdd .]
+
+ Description [Resize the number of pages allocated to store nodes in the BFS
+ traversal of the Bdd. The procedure moves the counter to the
+ next page when the end of the page is reached and allocates new
+ pages when necessary.]
+
+ SideEffects [Changes the size of pages, page, page index, maximum
+ number of pages freeing stuff in case of memory out. ]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+ResizeQueuePages(
+ )
+{
+ int i;
+ DdNode ***newQueuePages;
+
+ queuePage++;
+ /* If the current page index is larger than the number of pages
+ * allocated, allocate a new page array. Page numbers are incremented by
+ * INITIAL_PAGES
+ */
+ if (queuePage == maxQueuePages) {
+ newQueuePages = ALLOC(DdNode **,maxQueuePages + INITIAL_PAGES);
+ if (newQueuePages == NULL) {
+ for (i = 0; i < queuePage; i++) FREE(queuePages[i]);
+ FREE(queuePages);
+ memOut = 1;
+ return;
+ } else {
+ for (i = 0; i < maxQueuePages; i++) {
+ newQueuePages[i] = queuePages[i];
+ }
+ /* Increase total page count */
+ maxQueuePages += INITIAL_PAGES;
+ FREE(queuePages);
+ queuePages = newQueuePages;
+ }
+ }
+ /* Allocate a new page */
+ currentQueuePage = queuePages[queuePage] = ALLOC(DdNode *,queuePageSize);
+ if (currentQueuePage == NULL) {
+ for (i = 0; i < queuePage; i++) FREE(queuePages[i]);
+ FREE(queuePages);
+ memOut = 1;
+ return;
+ }
+ /* reset page index */
+ queuePageIndex = 0;
+ return;
+
+} /* end of ResizeQueuePages */
+
+
+/**Function********************************************************************
+
+ Synopsis [ Labels each node with its shortest distance from the root]
+
+ Description [ Labels each node with its shortest distance from the root.
+ This is done in a BFS search of the BDD. The nodes are processed
+ in a queue implemented as pages(array) to reduce memory fragmentation.
+ An entry is created for each node visited. The distance from the root
+ to the node with the corresponding parity is updated. The procedure
+ is called recursively each recusion level handling nodes at a given
+ level from the root.]
+
+
+ SideEffects [Creates entries in the pathTable]
+
+ SeeAlso [CreatePathTable CreateBotDist]
+
+******************************************************************************/
+static void
+CreateTopDist(
+ st_table * pathTable /* hast table to store path lengths */,
+ int parentPage /* the pointer to the page on which the first parent in the queue is to be found. */,
+ int parentQueueIndex /* pointer to the first parent on the page */,
+ int topLen /* current distance from the root */,
+ DdNode ** childPage /* pointer to the page on which the first child is to be added. */,
+ int childQueueIndex /* pointer to the first child */,
+ int numParents /* number of parents to process in this recursive call */,
+ FILE *fp /* where to write messages */)
+{
+ NodeDist_t *nodeStat;
+ DdNode *N, *Nv, *Nnv, *node, *child, *regChild;
+ int i;
+ int processingDone, childrenCount;
+
+#ifdef DD_DEBUG
+ numCalls++;
+
+ /* assume this procedure comes in with only the root node*/
+ /* set queue index to the next available entry for addition */
+ /* set queue page to page of addition */
+ if ((queuePages[parentPage] == childPage) && (parentQueueIndex ==
+ childQueueIndex)) {
+ fprintf(fp, "Should not happen that they are equal\n");
+ }
+ assert(queuePageIndex == childQueueIndex);
+ assert(currentQueuePage == childPage);
+#endif
+ /* number children added to queue is initialized , needed for
+ * numParents in the next call
+ */
+ childrenCount = 0;
+ /* process all the nodes in this level */
+ while (numParents) {
+ numParents--;
+ if (parentQueueIndex == queuePageSize) {
+ parentPage++;
+ parentQueueIndex = 0;
+ }
+ /* a parent to process */
+ node = *(queuePages[parentPage] + parentQueueIndex);
+ parentQueueIndex++;
+ /* get its children */
+ N = Cudd_Regular(node);
+ Nv = Cudd_T(N);
+ Nnv = Cudd_E(N);
+
+ Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
+ Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));
+
+ processingDone = 2;
+ while (processingDone) {
+ /* processing the THEN and the ELSE children, the THEN
+ * child first
+ */
+ if (processingDone == 2) {
+ child = Nv;
+ } else {
+ child = Nnv;
+ }
+
+ regChild = Cudd_Regular(child);
+ /* dont process if the child is a constant */
+ if (!Cudd_IsConstant(child)) {
+ /* check is already visited, if not add a new entry in
+ * the path Table
+ */
+ if (!st_lookup(pathTable, (char *)regChild, (char **)&nodeStat)) {
+ /* if not in table, has never been visited */
+ /* create entry for table */
+ if (nodeDistPageIndex == nodeDistPageSize)
+ ResizeNodeDistPages();
+ if (memOut) {
+ for (i = 0; i <= queuePage; i++) FREE(queuePages[i]);
+ FREE(queuePages);
+ st_free_table(pathTable);
+ return;
+ }
+ /* New entry for child in path Table is created here */
+ nodeStat = currentNodeDistPage + nodeDistPageIndex;
+ nodeDistPageIndex++;
+
+ /* Initialize fields of the node data */
+ nodeStat->oddTopDist = MAXSHORTINT;
+ nodeStat->evenTopDist = MAXSHORTINT;
+ nodeStat->evenBotDist = MAXSHORTINT;
+ nodeStat->oddBotDist = MAXSHORTINT;
+ nodeStat->regResult = NULL;
+ nodeStat->compResult = NULL;
+ /* update the table entry element, the distance keeps
+ * track of the parity of the path from the root
+ */
+ if (Cudd_IsComplement(child)) {
+ nodeStat->oddTopDist = (DdHalfWord) topLen + 1;
+ } else {
+ nodeStat->evenTopDist = (DdHalfWord) topLen + 1;
+ }
+
+ /* insert entry element for child in the table */
+ if (st_insert(pathTable, (char *)regChild,
+ (char *)nodeStat) == ST_OUT_OF_MEM) {
+ memOut = 1;
+ for (i = 0; i <= nodeDistPage; i++)
+ FREE(nodeDistPages[i]);
+ FREE(nodeDistPages);
+ for (i = 0; i <= queuePage; i++) FREE(queuePages[i]);
+ FREE(queuePages);
+ st_free_table(pathTable);
+ return;
+ }
+
+ /* Create list element for this child to process its children.
+ * If this node has been processed already, then it appears
+ * in the path table and hence is never added to the list
+ * again.
+ */
+
+ if (queuePageIndex == queuePageSize) ResizeQueuePages();
+ if (memOut) {
+ for (i = 0; i <= nodeDistPage; i++)
+ FREE(nodeDistPages[i]);
+ FREE(nodeDistPages);
+ st_free_table(pathTable);
+ return;
+ }
+ *(currentQueuePage + queuePageIndex) = child;
+ queuePageIndex++;
+
+ childrenCount++;
+ } else {
+ /* if not been met in a path with this parity before */
+ /* put in list */
+ if (((Cudd_IsComplement(child)) && (nodeStat->oddTopDist ==
+ MAXSHORTINT)) || ((!Cudd_IsComplement(child)) &&
+ (nodeStat->evenTopDist == MAXSHORTINT))) {
+
+ if (queuePageIndex == queuePageSize) ResizeQueuePages();
+ if (memOut) {
+ for (i = 0; i <= nodeDistPage; i++)
+ FREE(nodeDistPages[i]);
+ FREE(nodeDistPages);
+ st_free_table(pathTable);
+ return;
+
+ }
+ *(currentQueuePage + queuePageIndex) = child;
+ queuePageIndex++;
+
+ /* update the distance with the appropriate parity */
+ if (Cudd_IsComplement(child)) {
+ nodeStat->oddTopDist = (DdHalfWord) topLen + 1;
+ } else {
+ nodeStat->evenTopDist = (DdHalfWord) topLen + 1;
+ }
+ childrenCount++;
+ }
+
+ } /* end of else (not found in st_table) */
+ } /*end of if Not constant child */
+ processingDone--;
+ } /*end of while processing Nv, Nnv */
+ } /*end of while numParents */
+
+#ifdef DD_DEBUG
+ assert(queuePages[parentPage] == childPage);
+ assert(parentQueueIndex == childQueueIndex);
+#endif
+
+ if (childrenCount != 0) {
+ topLen++;
+ childPage = currentQueuePage;
+ childQueueIndex = queuePageIndex;
+ CreateTopDist(pathTable, parentPage, parentQueueIndex, topLen,
+ childPage, childQueueIndex, childrenCount, fp);
+ }
+
+ return;
+
+} /* end of CreateTopDist */
+
+
+/**Function********************************************************************
+
+ Synopsis [ Labels each node with the shortest distance from the constant.]
+
+ Description [Labels each node with the shortest distance from the constant.
+ This is done in a DFS search of the BDD. Each node has an odd
+ and even parity distance from the sink (since there exists paths to both
+ zero and one) which is less than MAXSHORTINT. At each node these distances
+ are updated using the minimum distance of its children from the constant.
+ SInce now both the length from the root and child is known, the minimum path
+ length(length of the shortest path between the root and the constant that
+ this node lies on) of this node can be calculated and used to update the
+ pathLengthArray]
+
+ SideEffects [Updates Path Table and path length array]
+
+ SeeAlso [CreatePathTable CreateTopDist AssessPathLength]
+
+******************************************************************************/
+static int
+CreateBotDist(
+ DdNode * node /* current node */,
+ st_table * pathTable /* path table with path lengths */,
+ unsigned int * pathLengthArray /* array that stores number of nodes belonging to a particular path length. */,
+ FILE *fp /* where to write messages */)
+{
+ DdNode *N, *Nv, *Nnv;
+ DdNode *realChild;
+ DdNode *child, *regChild;
+ NodeDist_t *nodeStat, *nodeStatChild;
+ unsigned int oddLen, evenLen, pathLength;
+ DdHalfWord botDist;
+ int processingDone;
+
+ if (Cudd_IsConstant(node))
+ return(1);
+ N = Cudd_Regular(node);
+ /* each node has one table entry */
+ /* update as you go down the min dist of each node from
+ the root in each (odd and even) parity */
+ if (!st_lookup(pathTable, (char *)N, (char **)&nodeStat)) {
+ fprintf(fp, "Something wrong, the entry doesn't exist\n");
+ return(0);
+ }
+
+ /* compute length of odd parity distances */
+ if ((nodeStat->oddTopDist != MAXSHORTINT) &&
+ (nodeStat->oddBotDist != MAXSHORTINT))
+ oddLen = (nodeStat->oddTopDist + nodeStat->oddBotDist);
+ else
+ oddLen = MAXSHORTINT;
+
+ /* compute length of even parity distances */
+ if (!((nodeStat->evenTopDist == MAXSHORTINT) ||
+ (nodeStat->evenBotDist == MAXSHORTINT)))
+ evenLen = (nodeStat->evenTopDist +nodeStat->evenBotDist);
+ else
+ evenLen = MAXSHORTINT;
+
+ /* assign pathlength to minimum of the two */
+ pathLength = (oddLen <= evenLen) ? oddLen : evenLen;
+
+ Nv = Cudd_T(N);
+ Nnv = Cudd_E(N);
+
+ /* process each child */
+ processingDone = 0;
+ while (processingDone != 2) {
+ if (!processingDone) {
+ child = Nv;
+ } else {
+ child = Nnv;
+ }
+
+ realChild = Cudd_NotCond(child, Cudd_IsComplement(node));
+ regChild = Cudd_Regular(child);
+ if (Cudd_IsConstant(realChild)) {
+ /* Found a minterm; count parity and shortest distance
+ ** from the constant.
+ */
+ if (Cudd_IsComplement(child))
+ nodeStat->oddBotDist = 1;
+ else
+ nodeStat->evenBotDist = 1;
+ } else {
+ /* If node not in table, recur. */
+ if (!st_lookup(pathTable, (char *) regChild,
+ (char **)&nodeStatChild)) {
+ fprintf(fp, "Something wrong, node in table should have been created in top dist proc.\n");
+ return(0);
+ }
+
+ if (nodeStatChild->oddBotDist == MAXSHORTINT) {
+ if (nodeStatChild->evenBotDist == MAXSHORTINT) {
+ if (!CreateBotDist(realChild, pathTable, pathLengthArray, fp))
+ return(0);
+ } else {
+ fprintf(fp, "Something wrong, both bot nodeStats should be there\n");
+ return(0);
+ }
+ }
+
+ /* Update shortest distance from the constant depending on
+ ** parity. */
+
+ if (Cudd_IsComplement(child)) {
+ /* If parity on the edge then add 1 to even distance
+ ** of child to get odd parity distance and add 1 to
+ ** odd distance of child to get even parity
+ ** distance. Change distance of current node only if
+ ** the calculated distance is less than existing
+ ** distance. */
+ if (nodeStatChild->oddBotDist != MAXSHORTINT)
+ botDist = nodeStatChild->oddBotDist + 1;
+ else
+ botDist = MAXSHORTINT;
+ if (nodeStat->evenBotDist > botDist )
+ nodeStat->evenBotDist = botDist;
+
+ if (nodeStatChild->evenBotDist != MAXSHORTINT)
+ botDist = nodeStatChild->evenBotDist + 1;
+ else
+ botDist = MAXSHORTINT;
+ if (nodeStat->oddBotDist > botDist)
+ nodeStat->oddBotDist = botDist;
+
+ } else {
+ /* If parity on the edge then add 1 to even distance
+ ** of child to get even parity distance and add 1 to
+ ** odd distance of child to get odd parity distance.
+ ** Change distance of current node only if the
+ ** calculated distance is lesser than existing
+ ** distance. */
+ if (nodeStatChild->evenBotDist != MAXSHORTINT)
+ botDist = nodeStatChild->evenBotDist + 1;
+ else
+ botDist = MAXSHORTINT;
+ if (nodeStat->evenBotDist > botDist)
+ nodeStat->evenBotDist = botDist;
+
+ if (nodeStatChild->oddBotDist != MAXSHORTINT)
+ botDist = nodeStatChild->oddBotDist + 1;
+ else
+ botDist = MAXSHORTINT;
+ if (nodeStat->oddBotDist > botDist)
+ nodeStat->oddBotDist = botDist;
+ }
+ } /* end of else (if not constant child ) */
+ processingDone++;
+ } /* end of while processing Nv, Nnv */
+
+ /* Compute shortest path length on the fly. */
+ if ((nodeStat->oddTopDist != MAXSHORTINT) &&
+ (nodeStat->oddBotDist != MAXSHORTINT))
+ oddLen = (nodeStat->oddTopDist + nodeStat->oddBotDist);
+ else
+ oddLen = MAXSHORTINT;
+
+ if ((nodeStat->evenTopDist != MAXSHORTINT) &&
+ (nodeStat->evenBotDist != MAXSHORTINT))
+ evenLen = (nodeStat->evenTopDist +nodeStat->evenBotDist);
+ else
+ evenLen = MAXSHORTINT;
+
+ /* Update path length array that has number of nodes of a particular
+ ** path length. */
+ if (oddLen < pathLength ) {
+ if (pathLength != MAXSHORTINT)
+ pathLengthArray[pathLength]--;
+ if (oddLen != MAXSHORTINT)
+ pathLengthArray[oddLen]++;
+ pathLength = oddLen;
+ }
+ if (evenLen < pathLength ) {
+ if (pathLength != MAXSHORTINT)
+ pathLengthArray[pathLength]--;
+ if (evenLen != MAXSHORTINT)
+ pathLengthArray[evenLen]++;
+ }
+
+ return(1);
+
+} /*end of CreateBotDist */
+
+
+/**Function********************************************************************
+
+ Synopsis [ The outer procedure to label each node with its shortest
+ distance from the root and constant]
+
+ Description [ The outer procedure to label each node with its shortest
+ distance from the root and constant. Calls CreateTopDist and CreateBotDist.
+ The basis for computing the distance between root and constant is that
+ the distance may be the sum of even distances from the node to the root
+ and constant or the sum of odd distances from the node to the root and
+ constant. Both CreateTopDist and CreateBotDist create the odd and
+ even parity distances from the root and constant respectively.]
+
+ SideEffects [None]
+
+ SeeAlso [CreateTopDist CreateBotDist]
+
+******************************************************************************/
+static st_table *
+CreatePathTable(
+ DdNode * node /* root of function */,
+ unsigned int * pathLengthArray /* array of path lengths to store nodes labeled with the various path lengths */,
+ FILE *fp /* where to write messages */)
+{
+
+ st_table *pathTable;
+ NodeDist_t *nodeStat;
+ DdHalfWord topLen;
+ DdNode *N;
+ int i, numParents;
+ int insertValue;
+ DdNode **childPage;
+ int parentPage;
+ int childQueueIndex, parentQueueIndex;
+
+ /* Creating path Table for storing data about nodes */
+ pathTable = st_init_table(st_ptrcmp,st_ptrhash);
+
+ /* initializing pages for info about each node */
+ maxNodeDistPages = INITIAL_PAGES;
+ nodeDistPages = ALLOC(NodeDist_t *, maxNodeDistPages);
+ if (nodeDistPages == NULL) {
+ goto OUT_OF_MEM;
+ }
+ nodeDistPage = 0;
+ currentNodeDistPage = nodeDistPages[nodeDistPage] =
+ ALLOC(NodeDist_t, nodeDistPageSize);
+ if (currentNodeDistPage == NULL) {
+ for (i = 0; i <= nodeDistPage; i++) FREE(nodeDistPages[i]);
+ FREE(nodeDistPages);
+ goto OUT_OF_MEM;
+ }
+ nodeDistPageIndex = 0;
+
+ /* Initializing pages for the BFS search queue, implemented as an array. */
+ maxQueuePages = INITIAL_PAGES;
+ queuePages = ALLOC(DdNode **, maxQueuePages);
+ if (queuePages == NULL) {
+ goto OUT_OF_MEM;
+ }
+ queuePage = 0;
+ currentQueuePage = queuePages[queuePage] = ALLOC(DdNode *, queuePageSize);
+ if (currentQueuePage == NULL) {
+ for (i = 0; i <= queuePage; i++) FREE(queuePages[i]);
+ FREE(queuePages);
+ goto OUT_OF_MEM;
+ }
+ queuePageIndex = 0;
+
+ /* Enter the root node into the queue to start with. */
+ parentPage = queuePage;
+ parentQueueIndex = queuePageIndex;
+ topLen = 0;
+ *(currentQueuePage + queuePageIndex) = node;
+ queuePageIndex++;
+ childPage = currentQueuePage;
+ childQueueIndex = queuePageIndex;
+
+ N = Cudd_Regular(node);
+
+ if (nodeDistPageIndex == nodeDistPageSize) ResizeNodeDistPages();
+ if (memOut) {
+ for (i = 0; i <= nodeDistPage; i++) FREE(nodeDistPages[i]);
+ FREE(nodeDistPages);
+ for (i = 0; i <= queuePage; i++) FREE(queuePages[i]);
+ FREE(queuePages);
+ st_free_table(pathTable);
+ goto OUT_OF_MEM;
+ }
+
+ nodeStat = currentNodeDistPage + nodeDistPageIndex;
+ nodeDistPageIndex++;
+
+ nodeStat->oddTopDist = MAXSHORTINT;
+ nodeStat->evenTopDist = MAXSHORTINT;
+ nodeStat->evenBotDist = MAXSHORTINT;
+ nodeStat->oddBotDist = MAXSHORTINT;
+ nodeStat->regResult = NULL;
+ nodeStat->compResult = NULL;
+
+ insertValue = st_insert(pathTable, (char *)N, (char *)nodeStat);
+ if (insertValue == ST_OUT_OF_MEM) {
+ memOut = 1;
+ for (i = 0; i <= nodeDistPage; i++) FREE(nodeDistPages[i]);
+ FREE(nodeDistPages);
+ for (i = 0; i <= queuePage; i++) FREE(queuePages[i]);
+ FREE(queuePages);
+ st_free_table(pathTable);
+ goto OUT_OF_MEM;
+ } else if (insertValue == 1) {
+ fprintf(fp, "Something wrong, the entry exists but didnt show up in st_lookup\n");
+ return(NULL);
+ }
+
+ if (Cudd_IsComplement(node)) {
+ nodeStat->oddTopDist = 0;
+ } else {
+ nodeStat->evenTopDist = 0;
+ }
+ numParents = 1;
+ /* call the function that counts the distance of each node from the
+ * root
+ */
+#ifdef DD_DEBUG
+ numCalls = 0;
+#endif
+ CreateTopDist(pathTable, parentPage, parentQueueIndex, (int) topLen,
+ childPage, childQueueIndex, numParents, fp);
+ if (memOut) {
+ fprintf(fp, "Out of Memory and cant count path lengths\n");
+ goto OUT_OF_MEM;
+ }
+
+#ifdef DD_DEBUG
+ numCalls = 0;
+#endif
+ /* call the function that counts the distance of each node from the
+ * constant
+ */
+ if (!CreateBotDist(node, pathTable, pathLengthArray, fp)) return(NULL);
+
+ /* free BFS queue pages as no longer required */
+ for (i = 0; i <= queuePage; i++) FREE(queuePages[i]);
+ FREE(queuePages);
+ return(pathTable);
+
+OUT_OF_MEM:
+ (void) fprintf(fp, "Out of Memory, cannot allocate pages\n");
+ memOut = 1;
+ return(NULL);
+
+} /*end of CreatePathTable */
+
+
+/**Function********************************************************************
+
+ Synopsis [Chooses the maximum allowable path length of nodes under the
+ threshold.]
+
+ Description [Chooses the maximum allowable path length under each node.
+ The corner cases are when the threshold is larger than the number
+ of nodes in the BDD iself, in which case 'numVars + 1' is returned.
+ If all nodes of a particular path length are needed, then the
+ maxpath returned is the next one with excess nodes = 0;]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static unsigned int
+AssessPathLength(
+ unsigned int * pathLengthArray /* array determining number of nodes belonging to the different path lengths */,
+ int threshold /* threshold to determine maximum allowable nodes in the subset */,
+ int numVars /* maximum number of variables */,
+ unsigned int * excess /* number of nodes labeled maxpath required in the subset */,
+ FILE *fp /* where to write messages */)
+{
+ unsigned int i, maxpath;
+ int temp;
+
+ temp = threshold;
+ i = 0;
+ maxpath = 0;
+ /* quit loop if i reaches max number of variables or if temp reaches
+ * below zero
+ */
+ while ((i < (unsigned) numVars+1) && (temp > 0)) {
+ if (pathLengthArray[i] > 0) {
+ maxpath = i;
+ temp = temp - pathLengthArray[i];
+ }
+ i++;
+ }
+ /* if all nodes of max path are needed */
+ if (temp >= 0) {
+ maxpath++; /* now maxpath becomes the next maxppath or max number
+ of variables */
+ *excess = 0;
+ } else { /* normal case when subset required is less than size of
+ original BDD */
+ *excess = temp + pathLengthArray[maxpath];
+ }
+
+ if (maxpath == 0) {
+ fprintf(fp, "Path Length array seems to be all zeroes, check\n");
+ }
+ return(maxpath);
+
+} /* end of AssessPathLength */
+
+
+/**Function********************************************************************
+
+ Synopsis [Builds the BDD with nodes labeled with path length less than or equal to maxpath]
+
+ Description [Builds the BDD with nodes labeled with path length
+ under maxpath and as many nodes labeled maxpath as determined by the
+ threshold. The procedure uses the path table to determine which nodes
+ in the original bdd need to be retained. This procedure picks a
+ shortest path (tie break decided by taking the child with the shortest
+ distance to the constant) and recurs down the path till it reaches the
+ constant. the procedure then starts building the subset upward from
+ the constant. All nodes labeled by path lengths less than the given
+ maxpath are used to build the subset. However, in the case of nodes
+ that have label equal to maxpath, as many are chosen as required by
+ the threshold. This number is stored in the info structure in the
+ field thresholdReached. This field is decremented whenever a node
+ labeled maxpath is encountered and the nodes labeled maxpath are
+ aggregated in a maxpath table. As soon as the thresholdReached count
+ goes to 0, the shortest path from this node to the constant is found.
+ The extraction of nodes with the above labeling is based on the fact
+ that each node, labeled with a path length, P, has at least one child
+ labeled P or less. So extracting all nodes labeled a given path length
+ P ensures complete paths between the root and the constant. Extraction
+ of a partial number of nodes with a given path length may result in
+ incomplete paths and hence the additional number of nodes are grabbed
+ to complete the path. Since the Bdd is built bottom-up, other nodes
+ labeled maxpath do lie on complete paths. The procedure may cause the
+ subset to have a larger or smaller number of nodes than the specified
+ threshold. The increase in the number of nodes is caused by the
+ building of a subset and the reduction by recombination. However in
+ most cases, the recombination overshadows the increase and the
+ procedure returns a result with lower number of nodes than specified.
+ The subsetNodeTable is NIL when there is no hard limit on the number
+ of nodes. Further efforts towards keeping the subset closer to the
+ threshold number were abandoned in favour of keeping the procedure
+ simple and fast.]
+
+ SideEffects [SubsetNodeTable is changed if it is not NIL.]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+BuildSubsetBdd(
+ DdManager * dd /* DD manager */,
+ st_table * pathTable /* path table with path lengths and computed results */,
+ DdNode * node /* current node */,
+ struct AssortedInfo * info /* assorted information structure */,
+ st_table * subsetNodeTable /* table storing computed results */)
+{
+ DdNode *N, *Nv, *Nnv;
+ DdNode *ThenBranch, *ElseBranch, *childBranch;
+ DdNode *child, *regChild, *regNnv, *regNv;
+ NodeDist_t *nodeStatNv, *nodeStat, *nodeStatNnv;
+ DdNode *neW, *topv, *regNew;
+ char *entry;
+ unsigned int topid;
+ unsigned int childPathLength, oddLen, evenLen, NnvPathLength, NvPathLength;
+ unsigned int NvBotDist, NnvBotDist;
+ int tiebreakChild;
+ int processingDone, thenDone, elseDone;
+
+
+#ifdef DD_DEBUG
+ numCalls++;
+#endif
+ if (Cudd_IsConstant(node))
+ return(node);
+
+ N = Cudd_Regular(node);
+ /* Find node in table. */
+ if (!st_lookup(pathTable, (char *)N, (char **)&nodeStat)) {
+ (void) fprintf(dd->err, "Something wrong, node must be in table \n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+ /* If the node in the table has been visited, then return the corresponding
+ ** Dd. Since a node can become a subset of itself, its
+ ** complement (that is te same node reached by a different parity) will
+ ** become a superset of the original node and result in some minterms
+ ** that were not in the original set. Hence two different results are
+ ** maintained, corresponding to the odd and even parities.
+ */
+
+ /* If this node is reached with an odd parity, get odd parity results. */
+ if (Cudd_IsComplement(node)) {
+ if (nodeStat->compResult != NULL) {
+#ifdef DD_DEBUG
+ hits++;
+#endif
+ return(nodeStat->compResult);
+ }
+ } else {
+ /* if this node is reached with an even parity, get even parity
+ * results
+ */
+ if (nodeStat->regResult != NULL) {
+#ifdef DD_DEBUG
+ hits++;
+#endif
+ return(nodeStat->regResult);
+ }
+ }
+
+
+ /* get children */
+ Nv = Cudd_T(N);
+ Nnv = Cudd_E(N);
+
+ Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
+ Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));
+
+ /* no child processed */
+ processingDone = 0;
+ /* then child not processed */
+ thenDone = 0;
+ ThenBranch = NULL;
+ /* else child not processed */
+ elseDone = 0;
+ ElseBranch = NULL;
+ /* if then child constant, branch is the child */
+ if (Cudd_IsConstant(Nv)) {
+ /*shortest path found */
+ if ((Nv == DD_ONE(dd)) && (info->findShortestPath)) {
+ info->findShortestPath = 0;
+ }
+
+ ThenBranch = Nv;
+ cuddRef(ThenBranch);
+ if (ThenBranch == NULL) {
+ return(NULL);
+ }
+
+ thenDone++;
+ processingDone++;
+ NvBotDist = MAXSHORTINT;
+ } else {
+ /* Derive regular child for table lookup. */
+ regNv = Cudd_Regular(Nv);
+ /* Get node data for shortest path length. */
+ if (!st_lookup(pathTable, (char *)regNv, (char **)&nodeStatNv) ) {
+ (void) fprintf(dd->err, "Something wrong, node must be in table\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+ /* Derive shortest path length for child. */
+ if ((nodeStatNv->oddTopDist != MAXSHORTINT) &&
+ (nodeStatNv->oddBotDist != MAXSHORTINT)) {
+ oddLen = (nodeStatNv->oddTopDist + nodeStatNv->oddBotDist);
+ } else {
+ oddLen = MAXSHORTINT;
+ }
+
+ if ((nodeStatNv->evenTopDist != MAXSHORTINT) &&
+ (nodeStatNv->evenBotDist != MAXSHORTINT)) {
+ evenLen = (nodeStatNv->evenTopDist +nodeStatNv->evenBotDist);
+ } else {
+ evenLen = MAXSHORTINT;
+ }
+
+ NvPathLength = (oddLen <= evenLen) ? oddLen : evenLen;
+ NvBotDist = (oddLen <= evenLen) ? nodeStatNv->oddBotDist:
+ nodeStatNv->evenBotDist;
+ }
+ /* if else child constant, branch is the child */
+ if (Cudd_IsConstant(Nnv)) {
+ /*shortest path found */
+ if ((Nnv == DD_ONE(dd)) && (info->findShortestPath)) {
+ info->findShortestPath = 0;
+ }
+
+ ElseBranch = Nnv;
+ cuddRef(ElseBranch);
+ if (ElseBranch == NULL) {
+ return(NULL);
+ }
+
+ elseDone++;
+ processingDone++;
+ NnvBotDist = MAXSHORTINT;
+ } else {
+ /* Derive regular child for table lookup. */
+ regNnv = Cudd_Regular(Nnv);
+ /* Get node data for shortest path length. */
+ if (!st_lookup(pathTable, (char *)regNnv, (char **)&nodeStatNnv) ) {
+ (void) fprintf(dd->err, "Something wrong, node must be in table\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+ /* Derive shortest path length for child. */
+ if ((nodeStatNnv->oddTopDist != MAXSHORTINT) &&
+ (nodeStatNnv->oddBotDist != MAXSHORTINT)) {
+ oddLen = (nodeStatNnv->oddTopDist + nodeStatNnv->oddBotDist);
+ } else {
+ oddLen = MAXSHORTINT;
+ }
+
+ if ((nodeStatNnv->evenTopDist != MAXSHORTINT) &&
+ (nodeStatNnv->evenBotDist != MAXSHORTINT)) {
+ evenLen = (nodeStatNnv->evenTopDist +nodeStatNnv->evenBotDist);
+ } else {
+ evenLen = MAXSHORTINT;
+ }
+
+ NnvPathLength = (oddLen <= evenLen) ? oddLen : evenLen;
+ NnvBotDist = (oddLen <= evenLen) ? nodeStatNnv->oddBotDist :
+ nodeStatNnv->evenBotDist;
+ }
+
+ tiebreakChild = (NvBotDist <= NnvBotDist) ? 1 : 0;
+ /* while both children not processed */
+ while (processingDone != 2) {
+ if (!processingDone) {
+ /* if no child processed */
+ /* pick the child with shortest path length and record which one
+ * picked
+ */
+ if ((NvPathLength < NnvPathLength) ||
+ ((NvPathLength == NnvPathLength) && (tiebreakChild == 1))) {
+ child = Nv;
+ regChild = regNv;
+ thenDone = 1;
+ childPathLength = NvPathLength;
+ } else {
+ child = Nnv;
+ regChild = regNnv;
+ elseDone = 1;
+ childPathLength = NnvPathLength;
+ } /* then path length less than else path length */
+ } else {
+ /* if one child processed, process the other */
+ if (thenDone) {
+ child = Nnv;
+ regChild = regNnv;
+ elseDone = 1;
+ childPathLength = NnvPathLength;
+ } else {
+ child = Nv;
+ regChild = regNv;
+ thenDone = 1;
+ childPathLength = NvPathLength;
+ } /* end of else pick the Then child if ELSE child processed */
+ } /* end of else one child has been processed */
+
+ /* ignore (replace with constant 0) all nodes which lie on paths larger
+ * than the maximum length of the path required
+ */
+ if (childPathLength > info->maxpath) {
+ /* record nodes visited */
+ childBranch = zero;
+ } else {
+ if (childPathLength < info->maxpath) {
+ if (info->findShortestPath) {
+ info->findShortestPath = 0;
+ }
+ childBranch = BuildSubsetBdd(dd, pathTable, child, info,
+ subsetNodeTable);
+
+ } else { /* Case: path length of node = maxpath */
+ /* If the node labeled with maxpath is found in the
+ ** maxpathTable, use it to build the subset BDD. */
+ if (st_lookup(info->maxpathTable, (char *)regChild,
+ (char **)&entry)) {
+ /* When a node that is already been chosen is hit,
+ ** the quest for a complete path is over. */
+ if (info->findShortestPath) {
+ info->findShortestPath = 0;
+ }
+ childBranch = BuildSubsetBdd(dd, pathTable, child, info,
+ subsetNodeTable);
+ } else {
+ /* If node is not found in the maxpathTable and
+ ** the threshold has been reached, then if the
+ ** path needs to be completed, continue. Else
+ ** replace the node with a zero. */
+ if (info->thresholdReached <= 0) {
+ if (info->findShortestPath) {
+ if (st_insert(info->maxpathTable, (char *)regChild,
+ (char *)NIL(char)) == ST_OUT_OF_MEM) {
+ memOut = 1;
+ (void) fprintf(dd->err, "OUT of memory\n");
+ info->thresholdReached = 0;
+ childBranch = zero;
+ } else {
+ info->thresholdReached--;
+ childBranch = BuildSubsetBdd(dd, pathTable,
+ child, info,subsetNodeTable);
+ }
+ } else { /* not find shortest path, we dont need this
+ node */
+ childBranch = zero;
+ }
+ } else { /* Threshold hasn't been reached,
+ ** need the node. */
+ if (st_insert(info->maxpathTable, (char *)regChild,
+ (char *)NIL(char)) == ST_OUT_OF_MEM) {
+ memOut = 1;
+ (void) fprintf(dd->err, "OUT of memory\n");
+ info->thresholdReached = 0;
+ childBranch = zero;
+ } else {
+ info->thresholdReached--;
+ if (info->thresholdReached <= 0) {
+ info->findShortestPath = 1;
+ }
+ childBranch = BuildSubsetBdd(dd, pathTable,
+ child, info, subsetNodeTable);
+
+ } /* end of st_insert successful */
+ } /* end of threshold hasnt been reached yet */
+ } /* end of else node not found in maxpath table */
+ } /* end of if (path length of node = maxpath) */
+ } /* end if !(childPathLength > maxpath) */
+ if (childBranch == NULL) {
+ /* deref other stuff incase reordering has taken place */
+ if (ThenBranch != NULL) {
+ Cudd_RecursiveDeref(dd, ThenBranch);
+ ThenBranch = NULL;
+ }
+ if (ElseBranch != NULL) {
+ Cudd_RecursiveDeref(dd, ElseBranch);
+ ElseBranch = NULL;
+ }
+ return(NULL);
+ }
+
+ cuddRef(childBranch);
+
+ if (child == Nv) {
+ ThenBranch = childBranch;
+ } else {
+ ElseBranch = childBranch;
+ }
+ processingDone++;
+
+ } /*end of while processing Nv, Nnv */
+
+ info->findShortestPath = 0;
+ topid = Cudd_NodeReadIndex(N);
+ topv = Cudd_ReadVars(dd, topid);
+ cuddRef(topv);
+ neW = cuddBddIteRecur(dd, topv, ThenBranch, ElseBranch);
+ if (neW != NULL) {
+ cuddRef(neW);
+ }
+ Cudd_RecursiveDeref(dd, topv);
+ Cudd_RecursiveDeref(dd, ThenBranch);
+ Cudd_RecursiveDeref(dd, ElseBranch);
+
+
+ /* Hard Limit of threshold has been imposed */
+ if (subsetNodeTable != NIL(st_table)) {
+ /* check if a new node is created */
+ regNew = Cudd_Regular(neW);
+ /* subset node table keeps all new nodes that have been created to keep
+ * a running count of how many nodes have been built in the subset.
+ */
+ if (!st_lookup(subsetNodeTable, (char *)regNew, (char **)&entry)) {
+ if (!Cudd_IsConstant(regNew)) {
+ if (st_insert(subsetNodeTable, (char *)regNew,
+ (char *)NULL) == ST_OUT_OF_MEM) {
+ (void) fprintf(dd->err, "Out of memory\n");
+ return (NULL);
+ }
+ if (st_count(subsetNodeTable) > info->threshold) {
+ info->thresholdReached = 0;
+ }
+ }
+ }
+ }
+
+
+ if (neW == NULL) {
+ return(NULL);
+ } else {
+ /*store computed result in regular form*/
+ if (Cudd_IsComplement(node)) {
+ nodeStat->compResult = neW;
+ cuddRef(nodeStat->compResult);
+ /* if the new node is the same as the corresponding node in the
+ * original bdd then its complement need not be computed as it
+ * cannot be larger than the node itself
+ */
+ if (neW == node) {
+#ifdef DD_DEBUG
+ thishit++;
+#endif
+ /* if a result for the node has already been computed, then
+ * it can only be smaller than teh node itself. hence store
+ * the node result in order not to break recombination
+ */
+ if (nodeStat->regResult != NULL) {
+ Cudd_RecursiveDeref(dd, nodeStat->regResult);
+ }
+ nodeStat->regResult = Cudd_Not(neW);
+ cuddRef(nodeStat->regResult);
+ }
+
+ } else {
+ nodeStat->regResult = neW;
+ cuddRef(nodeStat->regResult);
+ if (neW == node) {
+#ifdef DD_DEBUG
+ thishit++;
+#endif
+ if (nodeStat->compResult != NULL) {
+ Cudd_RecursiveDeref(dd, nodeStat->compResult);
+ }
+ nodeStat->compResult = Cudd_Not(neW);
+ cuddRef(nodeStat->compResult);
+ }
+ }
+
+ cuddDeref(neW);
+ return(neW);
+ } /* end of else i.e. Subset != NULL */
+} /* end of BuildSubsetBdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Procedure to free te result dds stored in the NodeDist pages.]
+
+ Description [None]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static enum st_retval
+stPathTableDdFree(
+ char * key,
+ char * value,
+ char * arg)
+{
+ NodeDist_t *nodeStat;
+ DdManager *dd;
+
+ nodeStat = (NodeDist_t *)value;
+ dd = (DdManager *)arg;
+ if (nodeStat->regResult != NULL) {
+ Cudd_RecursiveDeref(dd, nodeStat->regResult);
+ }
+ if (nodeStat->compResult != NULL) {
+ Cudd_RecursiveDeref(dd, nodeStat->compResult);
+ }
+ return(ST_CONTINUE);
+
+} /* end of stPathTableFree */
diff --git a/src/bdd/cudd/cuddSymmetry.c b/src/bdd/cudd/cuddSymmetry.c
new file mode 100644
index 00000000..7b2013e4
--- /dev/null
+++ b/src/bdd/cudd/cuddSymmetry.c
@@ -0,0 +1,1668 @@
+/**CFile***********************************************************************
+
+ FileName [cuddSymmetry.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions for symmetry-based variable reordering.]
+
+ Description [External procedures included in this file:
+ <ul>
+ <li> Cudd_SymmProfile()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddSymmCheck()
+ <li> cuddSymmSifting()
+ <li> cuddSymmSiftingConv()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> ddSymmUniqueCompare()
+ <li> ddSymmSiftingAux()
+ <li> ddSymmSiftingConvAux()
+ <li> ddSymmSiftingUp()
+ <li> ddSymmSiftingDown()
+ <li> ddSymmGroupMove()
+ <li> ddSymmGroupMoveBackward()
+ <li> ddSymmSiftingBackward()
+ <li> ddSymmSummary()
+ </ul>]
+
+ Author [Shipra Panda, Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define MV_OOM (Move *)1
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddSymmetry.c,v 1.1.1.1 2003/02/24 22:23:53 wjiang Exp $";
+#endif
+
+static int *entry;
+
+extern int ddTotalNumberSwapping;
+#ifdef DD_STATS
+extern int ddTotalNISwaps;
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int ddSymmUniqueCompare ARGS((int *ptrX, int *ptrY));
+static int ddSymmSiftingAux ARGS((DdManager *table, int x, int xLow, int xHigh));
+static int ddSymmSiftingConvAux ARGS((DdManager *table, int x, int xLow, int xHigh));
+static Move * ddSymmSiftingUp ARGS((DdManager *table, int y, int xLow));
+static Move * ddSymmSiftingDown ARGS((DdManager *table, int x, int xHigh));
+static int ddSymmGroupMove ARGS((DdManager *table, int x, int y, Move **moves));
+static int ddSymmGroupMoveBackward ARGS((DdManager *table, int x, int y));
+static int ddSymmSiftingBackward ARGS((DdManager *table, Move *moves, int size));
+static void ddSymmSummary ARGS((DdManager *table, int lower, int upper, int *symvars, int *symgroups));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints statistics on symmetric variables.]
+
+ Description []
+
+ SideEffects [None]
+
+******************************************************************************/
+void
+Cudd_SymmProfile(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int i,x,gbot;
+ int TotalSymm = 0;
+ int TotalSymmGroups = 0;
+
+ for (i = lower; i <= upper; i++) {
+ if (table->subtables[i].next != (unsigned) i) {
+ x = i;
+ (void) fprintf(table->out,"Group:");
+ do {
+ (void) fprintf(table->out," %d",table->invperm[x]);
+ TotalSymm++;
+ gbot = x;
+ x = table->subtables[x].next;
+ } while (x != i);
+ TotalSymmGroups++;
+#ifdef DD_DEBUG
+ assert(table->subtables[gbot].next == (unsigned) i);
+#endif
+ i = gbot;
+ (void) fprintf(table->out,"\n");
+ }
+ }
+ (void) fprintf(table->out,"Total Symmetric = %d\n",TotalSymm);
+ (void) fprintf(table->out,"Total Groups = %d\n",TotalSymmGroups);
+
+} /* end of Cudd_SymmProfile */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks for symmetry of x and y.]
+
+ Description [Checks for symmetry of x and y. Ignores projection
+ functions, unless they are isolated. Returns 1 in case of symmetry; 0
+ otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+int
+cuddSymmCheck(
+ DdManager * table,
+ int x,
+ int y)
+{
+ DdNode *f,*f0,*f1,*f01,*f00,*f11,*f10;
+ int comple; /* f0 is complemented */
+ int xsymmy; /* x and y may be positively symmetric */
+ int xsymmyp; /* x and y may be negatively symmetric */
+ int arccount; /* number of arcs from layer x to layer y */
+ int TotalRefCount; /* total reference count of layer y minus 1 */
+ int yindex;
+ int i;
+ DdNodePtr *list;
+ int slots;
+ DdNode *sentinel = &(table->sentinel);
+#ifdef DD_DEBUG
+ int xindex;
+#endif
+
+ /* Checks that x and y are not the projection functions.
+ ** For x it is sufficient to check whether there is only one
+ ** node; indeed, if there is one node, it is the projection function
+ ** and it cannot point to y. Hence, if y isn't just the projection
+ ** function, it has one arc coming from a layer different from x.
+ */
+ if (table->subtables[x].keys == 1) {
+ return(0);
+ }
+ yindex = table->invperm[y];
+ if (table->subtables[y].keys == 1) {
+ if (table->vars[yindex]->ref == 1)
+ return(0);
+ }
+
+ xsymmy = xsymmyp = 1;
+ arccount = 0;
+ slots = table->subtables[x].slots;
+ list = table->subtables[x].nodelist;
+ for (i = 0; i < slots; i++) {
+ f = list[i];
+ while (f != sentinel) {
+ /* Find f1, f0, f11, f10, f01, f00. */
+ f1 = cuddT(f);
+ f0 = Cudd_Regular(cuddE(f));
+ comple = Cudd_IsComplement(cuddE(f));
+ if ((int) f1->index == yindex) {
+ arccount++;
+ f11 = cuddT(f1); f10 = cuddE(f1);
+ } else {
+ if ((int) f0->index != yindex) {
+ /* If f is an isolated projection function it is
+ ** allowed to bypass layer y.
+ */
+ if (f1 != DD_ONE(table) || f0 != DD_ONE(table) || f->ref != 1)
+ return(0); /* f bypasses layer y */
+ }
+ f11 = f10 = f1;
+ }
+ if ((int) f0->index == yindex) {
+ arccount++;
+ f01 = cuddT(f0); f00 = cuddE(f0);
+ } else {
+ f01 = f00 = f0;
+ }
+ if (comple) {
+ f01 = Cudd_Not(f01);
+ f00 = Cudd_Not(f00);
+ }
+
+ if (f1 != DD_ONE(table) || f0 != DD_ONE(table) || f->ref != 1) {
+ xsymmy &= f01 == f10;
+ xsymmyp &= f11 == f00;
+ if ((xsymmy == 0) && (xsymmyp == 0))
+ return(0);
+ }
+
+ f = f->next;
+ } /* while */
+ } /* for */
+
+ /* Calculate the total reference counts of y */
+ TotalRefCount = -1; /* -1 for projection function */
+ slots = table->subtables[y].slots;
+ list = table->subtables[y].nodelist;
+ for (i = 0; i < slots; i++) {
+ f = list[i];
+ while (f != sentinel) {
+ TotalRefCount += f->ref;
+ f = f->next;
+ }
+ }
+
+#if defined(DD_DEBUG) && defined(DD_VERBOSE)
+ if (arccount == TotalRefCount) {
+ xindex = table->invperm[x];
+ (void) fprintf(table->out,
+ "Found symmetry! x =%d\ty = %d\tPos(%d,%d)\n",
+ xindex,yindex,x,y);
+ }
+#endif
+
+ return(arccount == TotalRefCount);
+
+} /* end of cuddSymmCheck */
+
+
+/**Function********************************************************************
+
+ Synopsis [Symmetric sifting algorithm.]
+
+ Description [Symmetric sifting algorithm.
+ Assumes that no dead nodes are present.
+ <ol>
+ <li> Order all the variables according to the number of entries in
+ each unique subtable.
+ <li> Sift the variable up and down, remembering each time the total
+ size of the DD heap and grouping variables that are symmetric.
+ <li> Select the best permutation.
+ <li> Repeat 3 and 4 for all variables.
+ </ol>
+ Returns 1 plus the number of symmetric variables if successful; 0
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddSymmSiftingConv]
+
+******************************************************************************/
+int
+cuddSymmSifting(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int i;
+ int *var;
+ int size;
+ int x;
+ int result;
+ int symvars;
+ int symgroups;
+#ifdef DD_STATS
+ int previousSize;
+#endif
+
+ size = table->size;
+
+ /* Find order in which to sift variables. */
+ var = NULL;
+ entry = ALLOC(int,size);
+ if (entry == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto ddSymmSiftingOutOfMem;
+ }
+ var = ALLOC(int,size);
+ if (var == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto ddSymmSiftingOutOfMem;
+ }
+
+ for (i = 0; i < size; i++) {
+ x = table->perm[i];
+ entry[i] = table->subtables[x].keys;
+ var[i] = i;
+ }
+
+ qsort((void *)var,size,sizeof(int),(int (*)(const void *, const void *))ddSymmUniqueCompare);
+
+ /* Initialize the symmetry of each subtable to itself. */
+ for (i = lower; i <= upper; i++) {
+ table->subtables[i].next = i;
+ }
+
+ for (i = 0; i < ddMin(table->siftMaxVar,size); i++) {
+ if (ddTotalNumberSwapping >= table->siftMaxSwap)
+ break;
+ x = table->perm[var[i]];
+#ifdef DD_STATS
+ previousSize = table->keys - table->isolated;
+#endif
+ if (x < lower || x > upper) continue;
+ if (table->subtables[x].next == (unsigned) x) {
+ result = ddSymmSiftingAux(table,x,lower,upper);
+ if (!result) goto ddSymmSiftingOutOfMem;
+#ifdef DD_STATS
+ if (table->keys < (unsigned) previousSize + table->isolated) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keys > (unsigned) previousSize +
+ table->isolated) {
+ (void) fprintf(table->out,"+"); /* should never happen */
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+ }
+
+ FREE(var);
+ FREE(entry);
+
+ ddSymmSummary(table, lower, upper, &symvars, &symgroups);
+
+#ifdef DD_STATS
+ (void) fprintf(table->out, "\n#:S_SIFTING %8d: symmetric variables\n",
+ symvars);
+ (void) fprintf(table->out, "#:G_SIFTING %8d: symmetric groups",
+ symgroups);
+#endif
+
+ return(1+symvars);
+
+ddSymmSiftingOutOfMem:
+
+ if (entry != NULL) FREE(entry);
+ if (var != NULL) FREE(var);
+
+ return(0);
+
+} /* end of cuddSymmSifting */
+
+
+/**Function********************************************************************
+
+ Synopsis [Symmetric sifting to convergence algorithm.]
+
+ Description [Symmetric sifting to convergence algorithm.
+ Assumes that no dead nodes are present.
+ <ol>
+ <li> Order all the variables according to the number of entries in
+ each unique subtable.
+ <li> Sift the variable up and down, remembering each time the total
+ size of the DD heap and grouping variables that are symmetric.
+ <li> Select the best permutation.
+ <li> Repeat 3 and 4 for all variables.
+ <li> Repeat 1-4 until no further improvement.
+ </ol>
+ Returns 1 plus the number of symmetric variables if successful; 0
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddSymmSifting]
+
+******************************************************************************/
+int
+cuddSymmSiftingConv(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int i;
+ int *var;
+ int size;
+ int x;
+ int result;
+ int symvars;
+ int symgroups;
+ int classes;
+ int initialSize;
+#ifdef DD_STATS
+ int previousSize;
+#endif
+
+ initialSize = table->keys - table->isolated;
+
+ size = table->size;
+
+ /* Find order in which to sift variables. */
+ var = NULL;
+ entry = ALLOC(int,size);
+ if (entry == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto ddSymmSiftingConvOutOfMem;
+ }
+ var = ALLOC(int,size);
+ if (var == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto ddSymmSiftingConvOutOfMem;
+ }
+
+ for (i = 0; i < size; i++) {
+ x = table->perm[i];
+ entry[i] = table->subtables[x].keys;
+ var[i] = i;
+ }
+
+ qsort((void *)var,size,sizeof(int),(int (*)(const void *, const void *))ddSymmUniqueCompare);
+
+ /* Initialize the symmetry of each subtable to itself
+ ** for first pass of converging symmetric sifting.
+ */
+ for (i = lower; i <= upper; i++) {
+ table->subtables[i].next = i;
+ }
+
+ for (i = 0; i < ddMin(table->siftMaxVar, table->size); i++) {
+ if (ddTotalNumberSwapping >= table->siftMaxSwap)
+ break;
+ x = table->perm[var[i]];
+ if (x < lower || x > upper) continue;
+ /* Only sift if not in symmetry group already. */
+ if (table->subtables[x].next == (unsigned) x) {
+#ifdef DD_STATS
+ previousSize = table->keys - table->isolated;
+#endif
+ result = ddSymmSiftingAux(table,x,lower,upper);
+ if (!result) goto ddSymmSiftingConvOutOfMem;
+#ifdef DD_STATS
+ if (table->keys < (unsigned) previousSize + table->isolated) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keys > (unsigned) previousSize +
+ table->isolated) {
+ (void) fprintf(table->out,"+");
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+ }
+
+ /* Sifting now until convergence. */
+ while ((unsigned) initialSize > table->keys - table->isolated) {
+ initialSize = table->keys - table->isolated;
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\n");
+#endif
+ /* Here we consider only one representative for each symmetry class. */
+ for (x = lower, classes = 0; x <= upper; x++, classes++) {
+ while ((unsigned) x < table->subtables[x].next) {
+ x = table->subtables[x].next;
+ }
+ /* Here x is the largest index in a group.
+ ** Groups consist of adjacent variables.
+ ** Hence, the next increment of x will move it to a new group.
+ */
+ i = table->invperm[x];
+ entry[i] = table->subtables[x].keys;
+ var[classes] = i;
+ }
+
+ qsort((void *)var,classes,sizeof(int),(int (*)(const void *, const void *))ddSymmUniqueCompare);
+
+ /* Now sift. */
+ for (i = 0; i < ddMin(table->siftMaxVar,classes); i++) {
+ if (ddTotalNumberSwapping >= table->siftMaxSwap)
+ break;
+ x = table->perm[var[i]];
+ if ((unsigned) x >= table->subtables[x].next) {
+#ifdef DD_STATS
+ previousSize = table->keys - table->isolated;
+#endif
+ result = ddSymmSiftingConvAux(table,x,lower,upper);
+ if (!result ) goto ddSymmSiftingConvOutOfMem;
+#ifdef DD_STATS
+ if (table->keys < (unsigned) previousSize + table->isolated) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keys > (unsigned) previousSize +
+ table->isolated) {
+ (void) fprintf(table->out,"+");
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+ } /* for */
+ }
+
+ ddSymmSummary(table, lower, upper, &symvars, &symgroups);
+
+#ifdef DD_STATS
+ (void) fprintf(table->out, "\n#:S_SIFTING %8d: symmetric variables\n",
+ symvars);
+ (void) fprintf(table->out, "#:G_SIFTING %8d: symmetric groups",
+ symgroups);
+#endif
+
+ FREE(var);
+ FREE(entry);
+
+ return(1+symvars);
+
+ddSymmSiftingConvOutOfMem:
+
+ if (entry != NULL) FREE(entry);
+ if (var != NULL) FREE(var);
+
+ return(0);
+
+} /* end of cuddSymmSiftingConv */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Comparison function used by qsort.]
+
+ Description [Comparison function used by qsort to order the variables
+ according to the number of keys in the subtables.
+ Returns the difference in number of keys between the two
+ variables being compared.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddSymmUniqueCompare(
+ int * ptrX,
+ int * ptrY)
+{
+#if 0
+ if (entry[*ptrY] == entry[*ptrX]) {
+ return((*ptrX) - (*ptrY));
+ }
+#endif
+ return(entry[*ptrY] - entry[*ptrX]);
+
+} /* end of ddSymmUniqueCompare */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given xLow <= x <= xHigh moves x up and down between the
+ boundaries.]
+
+ Description [Given xLow <= x <= xHigh moves x up and down between the
+ boundaries. Finds the best position and does the required changes.
+ Assumes that x is not part of a symmetry group. Returns 1 if
+ successful; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddSymmSiftingAux(
+ DdManager * table,
+ int x,
+ int xLow,
+ int xHigh)
+{
+ Move *move;
+ Move *moveUp; /* list of up moves */
+ Move *moveDown; /* list of down moves */
+ int initialSize;
+ int result;
+ int i;
+ int topbot; /* index to either top or bottom of symmetry group */
+ int initGroupSize, finalGroupSize;
+
+
+#ifdef DD_DEBUG
+ /* check for previously detected symmetry */
+ assert(table->subtables[x].next == (unsigned) x);
+#endif
+
+ initialSize = table->keys - table->isolated;
+
+ moveDown = NULL;
+ moveUp = NULL;
+
+ if ((x - xLow) > (xHigh - x)) {
+ /* Will go down first, unless x == xHigh:
+ ** Look for consecutive symmetries above x.
+ */
+ for (i = x; i > xLow; i--) {
+ if (!cuddSymmCheck(table,i-1,i))
+ break;
+ topbot = table->subtables[i-1].next; /* find top of i-1's group */
+ table->subtables[i-1].next = i;
+ table->subtables[x].next = topbot; /* x is bottom of group so its */
+ /* next is top of i-1's group */
+ i = topbot + 1; /* add 1 for i--; new i is top of symm group */
+ }
+ } else {
+ /* Will go up first unless x == xlow:
+ ** Look for consecutive symmetries below x.
+ */
+ for (i = x; i < xHigh; i++) {
+ if (!cuddSymmCheck(table,i,i+1))
+ break;
+ /* find bottom of i+1's symm group */
+ topbot = i + 1;
+ while ((unsigned) topbot < table->subtables[topbot].next) {
+ topbot = table->subtables[topbot].next;
+ }
+ table->subtables[topbot].next = table->subtables[i].next;
+ table->subtables[i].next = i + 1;
+ i = topbot - 1; /* subtract 1 for i++; new i is bottom of group */
+ }
+ }
+
+ /* Now x may be in the middle of a symmetry group.
+ ** Find bottom of x's symm group.
+ */
+ while ((unsigned) x < table->subtables[x].next)
+ x = table->subtables[x].next;
+
+ if (x == xLow) { /* Sift down */
+
+#ifdef DD_DEBUG
+ /* x must be a singleton */
+ assert((unsigned) x == table->subtables[x].next);
+#endif
+ if (x == xHigh) return(1); /* just one variable */
+
+ initGroupSize = 1;
+
+ moveDown = ddSymmSiftingDown(table,x,xHigh);
+ /* after this point x --> xHigh, unless early term */
+ if (moveDown == MV_OOM) goto ddSymmSiftingAuxOutOfMem;
+ if (moveDown == NULL) return(1);
+
+ x = moveDown->y;
+ /* Find bottom of x's group */
+ i = x;
+ while ((unsigned) i < table->subtables[i].next) {
+ i = table->subtables[i].next;
+ }
+#ifdef DD_DEBUG
+ /* x should be the top of the symmetry group and i the bottom */
+ assert((unsigned) i >= table->subtables[i].next);
+ assert((unsigned) x == table->subtables[i].next);
+#endif
+ finalGroupSize = i - x + 1;
+
+ if (initGroupSize == finalGroupSize) {
+ /* No new symmetry groups detected, return to best position */
+ result = ddSymmSiftingBackward(table,moveDown,initialSize);
+ } else {
+ initialSize = table->keys - table->isolated;
+ moveUp = ddSymmSiftingUp(table,x,xLow);
+ result = ddSymmSiftingBackward(table,moveUp,initialSize);
+ }
+ if (!result) goto ddSymmSiftingAuxOutOfMem;
+
+ } else if (cuddNextHigh(table,x) > xHigh) { /* Sift up */
+ /* Find top of x's symm group */
+ i = x; /* bottom */
+ x = table->subtables[x].next; /* top */
+
+ if (x == xLow) return(1); /* just one big group */
+
+ initGroupSize = i - x + 1;
+
+ moveUp = ddSymmSiftingUp(table,x,xLow);
+ /* after this point x --> xLow, unless early term */
+ if (moveUp == MV_OOM) goto ddSymmSiftingAuxOutOfMem;
+ if (moveUp == NULL) return(1);
+
+ x = moveUp->x;
+ /* Find top of x's group */
+ i = table->subtables[x].next;
+#ifdef DD_DEBUG
+ /* x should be the bottom of the symmetry group and i the top */
+ assert((unsigned) x >= table->subtables[x].next);
+ assert((unsigned) i == table->subtables[x].next);
+#endif
+ finalGroupSize = x - i + 1;
+
+ if (initGroupSize == finalGroupSize) {
+ /* No new symmetry groups detected, return to best position */
+ result = ddSymmSiftingBackward(table,moveUp,initialSize);
+ } else {
+ initialSize = table->keys - table->isolated;
+ moveDown = ddSymmSiftingDown(table,x,xHigh);
+ result = ddSymmSiftingBackward(table,moveDown,initialSize);
+ }
+ if (!result) goto ddSymmSiftingAuxOutOfMem;
+
+ } else if ((x - xLow) > (xHigh - x)) { /* must go down first: shorter */
+
+ moveDown = ddSymmSiftingDown(table,x,xHigh);
+ /* at this point x == xHigh, unless early term */
+ if (moveDown == MV_OOM) goto ddSymmSiftingAuxOutOfMem;
+
+ if (moveDown != NULL) {
+ x = moveDown->y; /* x is top here */
+ i = x;
+ while ((unsigned) i < table->subtables[i].next) {
+ i = table->subtables[i].next;
+ }
+ } else {
+ i = x;
+ while ((unsigned) i < table->subtables[i].next) {
+ i = table->subtables[i].next;
+ }
+ x = table->subtables[i].next;
+ }
+#ifdef DD_DEBUG
+ /* x should be the top of the symmetry group and i the bottom */
+ assert((unsigned) i >= table->subtables[i].next);
+ assert((unsigned) x == table->subtables[i].next);
+#endif
+ initGroupSize = i - x + 1;
+
+ moveUp = ddSymmSiftingUp(table,x,xLow);
+ if (moveUp == MV_OOM) goto ddSymmSiftingAuxOutOfMem;
+
+ if (moveUp != NULL) {
+ x = moveUp->x;
+ i = table->subtables[x].next;
+ } else {
+ i = x;
+ while ((unsigned) x < table->subtables[x].next)
+ x = table->subtables[x].next;
+ }
+#ifdef DD_DEBUG
+ /* x should be the bottom of the symmetry group and i the top */
+ assert((unsigned) x >= table->subtables[x].next);
+ assert((unsigned) i == table->subtables[x].next);
+#endif
+ finalGroupSize = x - i + 1;
+
+ if (initGroupSize == finalGroupSize) {
+ /* No new symmetry groups detected, return to best position */
+ result = ddSymmSiftingBackward(table,moveUp,initialSize);
+ } else {
+ while (moveDown != NULL) {
+ move = moveDown->next;
+ cuddDeallocNode(table, (DdNode *) moveDown);
+ moveDown = move;
+ }
+ initialSize = table->keys - table->isolated;
+ moveDown = ddSymmSiftingDown(table,x,xHigh);
+ result = ddSymmSiftingBackward(table,moveDown,initialSize);
+ }
+ if (!result) goto ddSymmSiftingAuxOutOfMem;
+
+ } else { /* moving up first: shorter */
+ /* Find top of x's symmetry group */
+ x = table->subtables[x].next;
+
+ moveUp = ddSymmSiftingUp(table,x,xLow);
+ /* at this point x == xHigh, unless early term */
+ if (moveUp == MV_OOM) goto ddSymmSiftingAuxOutOfMem;
+
+ if (moveUp != NULL) {
+ x = moveUp->x;
+ i = table->subtables[x].next;
+ } else {
+ while ((unsigned) x < table->subtables[x].next)
+ x = table->subtables[x].next;
+ i = table->subtables[x].next;
+ }
+#ifdef DD_DEBUG
+ /* x is bottom of the symmetry group and i is top */
+ assert((unsigned) x >= table->subtables[x].next);
+ assert((unsigned) i == table->subtables[x].next);
+#endif
+ initGroupSize = x - i + 1;
+
+ moveDown = ddSymmSiftingDown(table,x,xHigh);
+ if (moveDown == MV_OOM) goto ddSymmSiftingAuxOutOfMem;
+
+ if (moveDown != NULL) {
+ x = moveDown->y;
+ i = x;
+ while ((unsigned) i < table->subtables[i].next) {
+ i = table->subtables[i].next;
+ }
+ } else {
+ i = x;
+ x = table->subtables[x].next;
+ }
+#ifdef DD_DEBUG
+ /* x should be the top of the symmetry group and i the bottom */
+ assert((unsigned) i >= table->subtables[i].next);
+ assert((unsigned) x == table->subtables[i].next);
+#endif
+ finalGroupSize = i - x + 1;
+
+ if (initGroupSize == finalGroupSize) {
+ /* No new symmetries detected, go back to best position */
+ result = ddSymmSiftingBackward(table,moveDown,initialSize);
+ } else {
+ while (moveUp != NULL) {
+ move = moveUp->next;
+ cuddDeallocNode(table, (DdNode *) moveUp);
+ moveUp = move;
+ }
+ initialSize = table->keys - table->isolated;
+ moveUp = ddSymmSiftingUp(table,x,xLow);
+ result = ddSymmSiftingBackward(table,moveUp,initialSize);
+ }
+ if (!result) goto ddSymmSiftingAuxOutOfMem;
+ }
+
+ while (moveDown != NULL) {
+ move = moveDown->next;
+ cuddDeallocNode(table, (DdNode *) moveDown);
+ moveDown = move;
+ }
+ while (moveUp != NULL) {
+ move = moveUp->next;
+ cuddDeallocNode(table, (DdNode *) moveUp);
+ moveUp = move;
+ }
+
+ return(1);
+
+ddSymmSiftingAuxOutOfMem:
+ if (moveDown != MV_OOM) {
+ while (moveDown != NULL) {
+ move = moveDown->next;
+ cuddDeallocNode(table, (DdNode *) moveDown);
+ moveDown = move;
+ }
+ }
+ if (moveUp != MV_OOM) {
+ while (moveUp != NULL) {
+ move = moveUp->next;
+ cuddDeallocNode(table, (DdNode *) moveUp);
+ moveUp = move;
+ }
+ }
+
+ return(0);
+
+} /* end of ddSymmSiftingAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given xLow <= x <= xHigh moves x up and down between the
+ boundaries.]
+
+ Description [Given xLow <= x <= xHigh moves x up and down between the
+ boundaries. Finds the best position and does the required changes.
+ Assumes that x is either an isolated variable, or it is the bottom of
+ a symmetry group. All symmetries may not have been found, because of
+ exceeded growth limit. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddSymmSiftingConvAux(
+ DdManager * table,
+ int x,
+ int xLow,
+ int xHigh)
+{
+ Move *move;
+ Move *moveUp; /* list of up moves */
+ Move *moveDown; /* list of down moves */
+ int initialSize;
+ int result;
+ int i;
+ int initGroupSize, finalGroupSize;
+
+
+ initialSize = table->keys - table->isolated;
+
+ moveDown = NULL;
+ moveUp = NULL;
+
+ if (x == xLow) { /* Sift down */
+#ifdef DD_DEBUG
+ /* x is bottom of symmetry group */
+ assert((unsigned) x >= table->subtables[x].next);
+#endif
+ i = table->subtables[x].next;
+ initGroupSize = x - i + 1;
+
+ moveDown = ddSymmSiftingDown(table,x,xHigh);
+ /* at this point x == xHigh, unless early term */
+ if (moveDown == MV_OOM) goto ddSymmSiftingConvAuxOutOfMem;
+ if (moveDown == NULL) return(1);
+
+ x = moveDown->y;
+ i = x;
+ while ((unsigned) i < table->subtables[i].next) {
+ i = table->subtables[i].next;
+ }
+#ifdef DD_DEBUG
+ /* x should be the top of the symmetric group and i the bottom */
+ assert((unsigned) i >= table->subtables[i].next);
+ assert((unsigned) x == table->subtables[i].next);
+#endif
+ finalGroupSize = i - x + 1;
+
+ if (initGroupSize == finalGroupSize) {
+ /* No new symmetries detected, go back to best position */
+ result = ddSymmSiftingBackward(table,moveDown,initialSize);
+ } else {
+ initialSize = table->keys - table->isolated;
+ moveUp = ddSymmSiftingUp(table,x,xLow);
+ result = ddSymmSiftingBackward(table,moveUp,initialSize);
+ }
+ if (!result) goto ddSymmSiftingConvAuxOutOfMem;
+
+ } else if (cuddNextHigh(table,x) > xHigh) { /* Sift up */
+ /* Find top of x's symm group */
+ while ((unsigned) x < table->subtables[x].next)
+ x = table->subtables[x].next;
+ i = x; /* bottom */
+ x = table->subtables[x].next; /* top */
+
+ if (x == xLow) return(1);
+
+ initGroupSize = i - x + 1;
+
+ moveUp = ddSymmSiftingUp(table,x,xLow);
+ /* at this point x == xLow, unless early term */
+ if (moveUp == MV_OOM) goto ddSymmSiftingConvAuxOutOfMem;
+ if (moveUp == NULL) return(1);
+
+ x = moveUp->x;
+ i = table->subtables[x].next;
+#ifdef DD_DEBUG
+ /* x should be the bottom of the symmetry group and i the top */
+ assert((unsigned) x >= table->subtables[x].next);
+ assert((unsigned) i == table->subtables[x].next);
+#endif
+ finalGroupSize = x - i + 1;
+
+ if (initGroupSize == finalGroupSize) {
+ /* No new symmetry groups detected, return to best position */
+ result = ddSymmSiftingBackward(table,moveUp,initialSize);
+ } else {
+ initialSize = table->keys - table->isolated;
+ moveDown = ddSymmSiftingDown(table,x,xHigh);
+ result = ddSymmSiftingBackward(table,moveDown,initialSize);
+ }
+ if (!result)
+ goto ddSymmSiftingConvAuxOutOfMem;
+
+ } else if ((x - xLow) > (xHigh - x)) { /* must go down first: shorter */
+ moveDown = ddSymmSiftingDown(table,x,xHigh);
+ /* at this point x == xHigh, unless early term */
+ if (moveDown == MV_OOM) goto ddSymmSiftingConvAuxOutOfMem;
+
+ if (moveDown != NULL) {
+ x = moveDown->y;
+ i = x;
+ while ((unsigned) i < table->subtables[i].next) {
+ i = table->subtables[i].next;
+ }
+ } else {
+ while ((unsigned) x < table->subtables[x].next)
+ x = table->subtables[x].next;
+ i = x;
+ x = table->subtables[x].next;
+ }
+#ifdef DD_DEBUG
+ /* x should be the top of the symmetry group and i the bottom */
+ assert((unsigned) i >= table->subtables[i].next);
+ assert((unsigned) x == table->subtables[i].next);
+#endif
+ initGroupSize = i - x + 1;
+
+ moveUp = ddSymmSiftingUp(table,x,xLow);
+ if (moveUp == MV_OOM) goto ddSymmSiftingConvAuxOutOfMem;
+
+ if (moveUp != NULL) {
+ x = moveUp->x;
+ i = table->subtables[x].next;
+ } else {
+ i = x;
+ while ((unsigned) x < table->subtables[x].next)
+ x = table->subtables[x].next;
+ }
+#ifdef DD_DEBUG
+ /* x should be the bottom of the symmetry group and i the top */
+ assert((unsigned) x >= table->subtables[x].next);
+ assert((unsigned) i == table->subtables[x].next);
+#endif
+ finalGroupSize = x - i + 1;
+
+ if (initGroupSize == finalGroupSize) {
+ /* No new symmetry groups detected, return to best position */
+ result = ddSymmSiftingBackward(table,moveUp,initialSize);
+ } else {
+ while (moveDown != NULL) {
+ move = moveDown->next;
+ cuddDeallocNode(table, (DdNode *) moveDown);
+ moveDown = move;
+ }
+ initialSize = table->keys - table->isolated;
+ moveDown = ddSymmSiftingDown(table,x,xHigh);
+ result = ddSymmSiftingBackward(table,moveDown,initialSize);
+ }
+ if (!result) goto ddSymmSiftingConvAuxOutOfMem;
+
+ } else { /* moving up first: shorter */
+ /* Find top of x's symmetry group */
+ x = table->subtables[x].next;
+
+ moveUp = ddSymmSiftingUp(table,x,xLow);
+ /* at this point x == xHigh, unless early term */
+ if (moveUp == MV_OOM) goto ddSymmSiftingConvAuxOutOfMem;
+
+ if (moveUp != NULL) {
+ x = moveUp->x;
+ i = table->subtables[x].next;
+ } else {
+ i = x;
+ while ((unsigned) x < table->subtables[x].next)
+ x = table->subtables[x].next;
+ }
+#ifdef DD_DEBUG
+ /* x is bottom of the symmetry group and i is top */
+ assert((unsigned) x >= table->subtables[x].next);
+ assert((unsigned) i == table->subtables[x].next);
+#endif
+ initGroupSize = x - i + 1;
+
+ moveDown = ddSymmSiftingDown(table,x,xHigh);
+ if (moveDown == MV_OOM) goto ddSymmSiftingConvAuxOutOfMem;
+
+ if (moveDown != NULL) {
+ x = moveDown->y;
+ i = x;
+ while ((unsigned) i < table->subtables[i].next) {
+ i = table->subtables[i].next;
+ }
+ } else {
+ i = x;
+ x = table->subtables[x].next;
+ }
+#ifdef DD_DEBUG
+ /* x should be the top of the symmetry group and i the bottom */
+ assert((unsigned) i >= table->subtables[i].next);
+ assert((unsigned) x == table->subtables[i].next);
+#endif
+ finalGroupSize = i - x + 1;
+
+ if (initGroupSize == finalGroupSize) {
+ /* No new symmetries detected, go back to best position */
+ result = ddSymmSiftingBackward(table,moveDown,initialSize);
+ } else {
+ while (moveUp != NULL) {
+ move = moveUp->next;
+ cuddDeallocNode(table, (DdNode *) moveUp);
+ moveUp = move;
+ }
+ initialSize = table->keys - table->isolated;
+ moveUp = ddSymmSiftingUp(table,x,xLow);
+ result = ddSymmSiftingBackward(table,moveUp,initialSize);
+ }
+ if (!result) goto ddSymmSiftingConvAuxOutOfMem;
+ }
+
+ while (moveDown != NULL) {
+ move = moveDown->next;
+ cuddDeallocNode(table, (DdNode *) moveDown);
+ moveDown = move;
+ }
+ while (moveUp != NULL) {
+ move = moveUp->next;
+ cuddDeallocNode(table, (DdNode *) moveUp);
+ moveUp = move;
+ }
+
+ return(1);
+
+ddSymmSiftingConvAuxOutOfMem:
+ if (moveDown != MV_OOM) {
+ while (moveDown != NULL) {
+ move = moveDown->next;
+ cuddDeallocNode(table, (DdNode *) moveDown);
+ moveDown = move;
+ }
+ }
+ if (moveUp != MV_OOM) {
+ while (moveUp != NULL) {
+ move = moveUp->next;
+ cuddDeallocNode(table, (DdNode *) moveUp);
+ moveUp = move;
+ }
+ }
+
+ return(0);
+
+} /* end of ddSymmSiftingConvAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Moves x up until either it reaches the bound (xLow) or
+ the size of the DD heap increases too much.]
+
+ Description [Moves x up until either it reaches the bound (xLow) or
+ the size of the DD heap increases too much. Assumes that x is the top
+ of a symmetry group. Checks x for symmetry to the adjacent
+ variables. If symmetry is found, the symmetry group of x is merged
+ with the symmetry group of the other variable. Returns the set of
+ moves in case of success; MV_OOM if memory is full.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static Move *
+ddSymmSiftingUp(
+ DdManager * table,
+ int y,
+ int xLow)
+{
+ Move *moves;
+ Move *move;
+ int x;
+ int size;
+ int i;
+ int gxtop,gybot;
+ int limitSize;
+ int xindex, yindex;
+ int zindex;
+ int z;
+ int isolated;
+ int L; /* lower bound on DD size */
+#ifdef DD_DEBUG
+ int checkL;
+#endif
+
+
+ moves = NULL;
+ yindex = table->invperm[y];
+
+ /* Initialize the lower bound.
+ ** The part of the DD below the bottom of y' group will not change.
+ ** The part of the DD above y that does not interact with y will not
+ ** change. The rest may vanish in the best case, except for
+ ** the nodes at level xLow, which will not vanish, regardless.
+ */
+ limitSize = L = table->keys - table->isolated;
+ gybot = y;
+ while ((unsigned) gybot < table->subtables[gybot].next)
+ gybot = table->subtables[gybot].next;
+ for (z = xLow + 1; z <= gybot; z++) {
+ zindex = table->invperm[z];
+ if (zindex == yindex || cuddTestInteract(table,zindex,yindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ L -= table->subtables[z].keys - isolated;
+ }
+ }
+
+ x = cuddNextLow(table,y);
+ while (x >= xLow && L <= limitSize) {
+#ifdef DD_DEBUG
+ gybot = y;
+ while ((unsigned) gybot < table->subtables[gybot].next)
+ gybot = table->subtables[gybot].next;
+ checkL = table->keys - table->isolated;
+ for (z = xLow + 1; z <= gybot; z++) {
+ zindex = table->invperm[z];
+ if (zindex == yindex || cuddTestInteract(table,zindex,yindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ checkL -= table->subtables[z].keys - isolated;
+ }
+ }
+ assert(L == checkL);
+#endif
+ gxtop = table->subtables[x].next;
+ if (cuddSymmCheck(table,x,y)) {
+ /* Symmetry found, attach symm groups */
+ table->subtables[x].next = y;
+ i = table->subtables[y].next;
+ while (table->subtables[i].next != (unsigned) y)
+ i = table->subtables[i].next;
+ table->subtables[i].next = gxtop;
+ } else if (table->subtables[x].next == (unsigned) x &&
+ table->subtables[y].next == (unsigned) y) {
+ /* x and y have self symmetry */
+ xindex = table->invperm[x];
+ size = cuddSwapInPlace(table,x,y);
+#ifdef DD_DEBUG
+ assert(table->subtables[x].next == (unsigned) x);
+ assert(table->subtables[y].next == (unsigned) y);
+#endif
+ if (size == 0) goto ddSymmSiftingUpOutOfMem;
+ /* Update the lower bound. */
+ if (cuddTestInteract(table,xindex,yindex)) {
+ isolated = table->vars[xindex]->ref == 1;
+ L += table->subtables[y].keys - isolated;
+ }
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddSymmSiftingUpOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ if ((double) size > (double) limitSize * table->maxGrowth)
+ return(moves);
+ if (size < limitSize) limitSize = size;
+ } else { /* Group move */
+ size = ddSymmGroupMove(table,x,y,&moves);
+ if (size == 0) goto ddSymmSiftingUpOutOfMem;
+ /* Update the lower bound. */
+ z = moves->y;
+ do {
+ zindex = table->invperm[z];
+ if (cuddTestInteract(table,zindex,yindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ L += table->subtables[z].keys - isolated;
+ }
+ z = table->subtables[z].next;
+ } while (z != (int) moves->y);
+ if ((double) size > (double) limitSize * table->maxGrowth)
+ return(moves);
+ if (size < limitSize) limitSize = size;
+ }
+ y = gxtop;
+ x = cuddNextLow(table,y);
+ }
+
+ return(moves);
+
+ddSymmSiftingUpOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+ return(MV_OOM);
+
+} /* end of ddSymmSiftingUp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Moves x down until either it reaches the bound (xHigh) or
+ the size of the DD heap increases too much.]
+
+ Description [Moves x down until either it reaches the bound (xHigh)
+ or the size of the DD heap increases too much. Assumes that x is the
+ bottom of a symmetry group. Checks x for symmetry to the adjacent
+ variables. If symmetry is found, the symmetry group of x is merged
+ with the symmetry group of the other variable. Returns the set of
+ moves in case of success; MV_OOM if memory is full.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static Move *
+ddSymmSiftingDown(
+ DdManager * table,
+ int x,
+ int xHigh)
+{
+ Move *moves;
+ Move *move;
+ int y;
+ int size;
+ int limitSize;
+ int gxtop,gybot;
+ int R; /* upper bound on node decrease */
+ int xindex, yindex;
+ int isolated;
+ int z;
+ int zindex;
+#ifdef DD_DEBUG
+ int checkR;
+#endif
+
+ moves = NULL;
+ /* Initialize R */
+ xindex = table->invperm[x];
+ gxtop = table->subtables[x].next;
+ limitSize = size = table->keys - table->isolated;
+ R = 0;
+ for (z = xHigh; z > gxtop; z--) {
+ zindex = table->invperm[z];
+ if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ R += table->subtables[z].keys - isolated;
+ }
+ }
+
+ y = cuddNextHigh(table,x);
+ while (y <= xHigh && size - R < limitSize) {
+#ifdef DD_DEBUG
+ gxtop = table->subtables[x].next;
+ checkR = 0;
+ for (z = xHigh; z > gxtop; z--) {
+ zindex = table->invperm[z];
+ if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ checkR += table->subtables[z].keys - isolated;
+ }
+ }
+ assert(R == checkR);
+#endif
+ gybot = table->subtables[y].next;
+ while (table->subtables[gybot].next != (unsigned) y)
+ gybot = table->subtables[gybot].next;
+ if (cuddSymmCheck(table,x,y)) {
+ /* Symmetry found, attach symm groups */
+ gxtop = table->subtables[x].next;
+ table->subtables[x].next = y;
+ table->subtables[gybot].next = gxtop;
+ } else if (table->subtables[x].next == (unsigned) x &&
+ table->subtables[y].next == (unsigned) y) {
+ /* x and y have self symmetry */
+ /* Update upper bound on node decrease. */
+ yindex = table->invperm[y];
+ if (cuddTestInteract(table,xindex,yindex)) {
+ isolated = table->vars[yindex]->ref == 1;
+ R -= table->subtables[y].keys - isolated;
+ }
+ size = cuddSwapInPlace(table,x,y);
+#ifdef DD_DEBUG
+ assert(table->subtables[x].next == (unsigned) x);
+ assert(table->subtables[y].next == (unsigned) y);
+#endif
+ if (size == 0) goto ddSymmSiftingDownOutOfMem;
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto ddSymmSiftingDownOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ if ((double) size > (double) limitSize * table->maxGrowth)
+ return(moves);
+ if (size < limitSize) limitSize = size;
+ } else { /* Group move */
+ /* Update upper bound on node decrease: first phase. */
+ gxtop = table->subtables[x].next;
+ z = gxtop + 1;
+ do {
+ zindex = table->invperm[z];
+ if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ R -= table->subtables[z].keys - isolated;
+ }
+ z++;
+ } while (z <= gybot);
+ size = ddSymmGroupMove(table,x,y,&moves);
+ if (size == 0) goto ddSymmSiftingDownOutOfMem;
+ if ((double) size > (double) limitSize * table->maxGrowth)
+ return(moves);
+ if (size < limitSize) limitSize = size;
+ /* Update upper bound on node decrease: second phase. */
+ gxtop = table->subtables[gybot].next;
+ for (z = gxtop + 1; z <= gybot; z++) {
+ zindex = table->invperm[z];
+ if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
+ isolated = table->vars[zindex]->ref == 1;
+ R += table->subtables[z].keys - isolated;
+ }
+ }
+ }
+ x = gybot;
+ y = cuddNextHigh(table,x);
+ }
+
+ return(moves);
+
+ddSymmSiftingDownOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+ return(MV_OOM);
+
+} /* end of ddSymmSiftingDown */
+
+
+/**Function********************************************************************
+
+ Synopsis [Swaps two groups.]
+
+ Description [Swaps two groups. x is assumed to be the bottom variable
+ of the first group. y is assumed to be the top variable of the second
+ group. Updates the list of moves. Returns the number of keys in the
+ table if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddSymmGroupMove(
+ DdManager * table,
+ int x,
+ int y,
+ Move ** moves)
+{
+ Move *move;
+ int size;
+ int i,j;
+ int xtop,xbot,xsize,ytop,ybot,ysize,newxtop;
+ int swapx,swapy;
+
+#if DD_DEBUG
+ assert(x < y); /* we assume that x < y */
+#endif
+ /* Find top, bottom, and size for the two groups. */
+ xbot = x;
+ xtop = table->subtables[x].next;
+ xsize = xbot - xtop + 1;
+ ybot = y;
+ while ((unsigned) ybot < table->subtables[ybot].next)
+ ybot = table->subtables[ybot].next;
+ ytop = y;
+ ysize = ybot - ytop + 1;
+
+ /* Sift the variables of the second group up through the first group. */
+ for (i = 1; i <= ysize; i++) {
+ for (j = 1; j <= xsize; j++) {
+ size = cuddSwapInPlace(table,x,y);
+ if (size == 0) return(0);
+ swapx = x; swapy = y;
+ y = x;
+ x = y - 1;
+ }
+ y = ytop + i;
+ x = y - 1;
+ }
+
+ /* fix symmetries */
+ y = xtop; /* ytop is now where xtop used to be */
+ for (i = 0; i < ysize-1 ; i++) {
+ table->subtables[y].next = y + 1;
+ y = y + 1;
+ }
+ table->subtables[y].next = xtop; /* y is bottom of its group, join */
+ /* its symmetry to top of its group */
+ x = y + 1;
+ newxtop = x;
+ for (i = 0; i < xsize - 1 ; i++) {
+ table->subtables[x].next = x + 1;
+ x = x + 1;
+ }
+ table->subtables[x].next = newxtop; /* x is bottom of its group, join */
+ /* its symmetry to top of its group */
+ /* Store group move */
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) return(0);
+ move->x = swapx;
+ move->y = swapy;
+ move->size = size;
+ move->next = *moves;
+ *moves = move;
+
+ return(size);
+
+} /* end of ddSymmGroupMove */
+
+
+/**Function********************************************************************
+
+ Synopsis [Undoes the swap of two groups.]
+
+ Description [Undoes the swap of two groups. x is assumed to be the
+ bottom variable of the first group. y is assumed to be the top
+ variable of the second group. Returns the number of keys in the table
+ if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddSymmGroupMoveBackward(
+ DdManager * table,
+ int x,
+ int y)
+{
+ int size;
+ int i,j;
+ int xtop,xbot,xsize,ytop,ybot,ysize,newxtop;
+
+#if DD_DEBUG
+ assert(x < y); /* We assume that x < y */
+#endif
+
+ /* Find top, bottom, and size for the two groups. */
+ xbot = x;
+ xtop = table->subtables[x].next;
+ xsize = xbot - xtop + 1;
+ ybot = y;
+ while ((unsigned) ybot < table->subtables[ybot].next)
+ ybot = table->subtables[ybot].next;
+ ytop = y;
+ ysize = ybot - ytop + 1;
+
+ /* Sift the variables of the second group up through the first group. */
+ for (i = 1; i <= ysize; i++) {
+ for (j = 1; j <= xsize; j++) {
+ size = cuddSwapInPlace(table,x,y);
+ if (size == 0) return(0);
+ y = x;
+ x = cuddNextLow(table,y);
+ }
+ y = ytop + i;
+ x = y - 1;
+ }
+
+ /* Fix symmetries. */
+ y = xtop;
+ for (i = 0; i < ysize-1 ; i++) {
+ table->subtables[y].next = y + 1;
+ y = y + 1;
+ }
+ table->subtables[y].next = xtop; /* y is bottom of its group, join */
+ /* its symmetry to top of its group */
+ x = y + 1;
+ newxtop = x;
+ for (i = 0; i < xsize-1 ; i++) {
+ table->subtables[x].next = x + 1;
+ x = x + 1;
+ }
+ table->subtables[x].next = newxtop; /* x is bottom of its group, join */
+ /* its symmetry to top of its group */
+
+ return(size);
+
+} /* end of ddSymmGroupMoveBackward */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given a set of moves, returns the DD heap to the position
+ giving the minimum size.]
+
+ Description [Given a set of moves, returns the DD heap to the
+ position giving the minimum size. In case of ties, returns to the
+ closest position giving the minimum size. Returns 1 in case of
+ success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddSymmSiftingBackward(
+ DdManager * table,
+ Move * moves,
+ int size)
+{
+ Move *move;
+ int res;
+
+ for (move = moves; move != NULL; move = move->next) {
+ if (move->size < size) {
+ size = move->size;
+ }
+ }
+
+ for (move = moves; move != NULL; move = move->next) {
+ if (move->size == size) return(1);
+ if (table->subtables[move->x].next == move->x && table->subtables[move->y].next == move->y) {
+ res = cuddSwapInPlace(table,(int)move->x,(int)move->y);
+#ifdef DD_DEBUG
+ assert(table->subtables[move->x].next == move->x);
+ assert(table->subtables[move->y].next == move->y);
+#endif
+ } else { /* Group move necessary */
+ res = ddSymmGroupMoveBackward(table,(int)move->x,(int)move->y);
+ }
+ if (!res) return(0);
+ }
+
+ return(1);
+
+} /* end of ddSymmSiftingBackward */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts numbers of symmetric variables and symmetry
+ groups.]
+
+ Description []
+
+ SideEffects [None]
+
+******************************************************************************/
+static void
+ddSymmSummary(
+ DdManager * table,
+ int lower,
+ int upper,
+ int * symvars,
+ int * symgroups)
+{
+ int i,x,gbot;
+ int TotalSymm = 0;
+ int TotalSymmGroups = 0;
+
+ for (i = lower; i <= upper; i++) {
+ if (table->subtables[i].next != (unsigned) i) {
+ TotalSymmGroups++;
+ x = i;
+ do {
+ TotalSymm++;
+ gbot = x;
+ x = table->subtables[x].next;
+ } while (x != i);
+#ifdef DD_DEBUG
+ assert(table->subtables[gbot].next == (unsigned) i);
+#endif
+ i = gbot;
+ }
+ }
+ *symvars = TotalSymm;
+ *symgroups = TotalSymmGroups;
+
+ return;
+
+} /* end of ddSymmSummary */
diff --git a/src/bdd/cudd/cuddTable.c b/src/bdd/cudd/cuddTable.c
new file mode 100644
index 00000000..b118b76a
--- /dev/null
+++ b/src/bdd/cudd/cuddTable.c
@@ -0,0 +1,3141 @@
+/**CFile***********************************************************************
+
+ FileName [cuddTable.c]
+
+ PackageName [cudd]
+
+ Synopsis [Unique table management functions.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_Prime()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddAllocNode()
+ <li> cuddInitTable()
+ <li> cuddFreeTable()
+ <li> cuddGarbageCollect()
+ <li> cuddGarbageCollectZdd()
+ <li> cuddZddGetNode()
+ <li> cuddZddGetNodeIVO()
+ <li> cuddUniqueInter()
+ <li> cuddUniqueInterIVO()
+ <li> cuddUniqueInterZdd()
+ <li> cuddUniqueConst()
+ <li> cuddRehash()
+ <li> cuddShrinkSubtable()
+ <li> cuddInsertSubtables()
+ <li> cuddDestroySubtables()
+ <li> cuddResizeTableZdd()
+ <li> cuddSlowTableGrowth()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> ddRehashZdd()
+ <li> ddResizeTable()
+ <li> cuddFindParent()
+ <li> cuddOrderedInsert()
+ <li> cuddOrderedThread()
+ <li> cuddRotateLeft()
+ <li> cuddRotateRight()
+ <li> cuddDoRebalance()
+ <li> cuddCheckCollisionOrdering()
+ </ul>]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef DD_UNSORTED_FREE_LIST
+/* Constants for red/black trees. */
+#define DD_STACK_SIZE 128
+#define DD_RED 0
+#define DD_BLACK 1
+#define DD_PAGE_SIZE 8192
+#define DD_PAGE_MASK ~(DD_PAGE_SIZE - 1)
+#define DD_INSERT_COMPARE(x,y) \
+ (((ptruint) (x) & DD_PAGE_MASK) - ((ptruint) (y) & DD_PAGE_MASK))
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/* This is a hack for when CUDD_VALUE_TYPE is double */
+typedef union hack {
+ CUDD_VALUE_TYPE value;
+ unsigned int bits[2];
+} hack;
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddTable.c,v 1.1.1.1 2003/02/24 22:23:53 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+#ifndef DD_UNSORTED_FREE_LIST
+/* Macros for red/black trees. */
+#define DD_COLOR(p) ((p)->index)
+#define DD_IS_BLACK(p) ((p)->index == DD_BLACK)
+#define DD_IS_RED(p) ((p)->index == DD_RED)
+#define DD_LEFT(p) cuddT(p)
+#define DD_RIGHT(p) cuddE(p)
+#define DD_NEXT(p) ((p)->next)
+#endif
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static void ddRehashZdd ARGS((DdManager *unique, int i));
+static int ddResizeTable ARGS((DdManager *unique, int index));
+static int cuddFindParent ARGS((DdManager *table, DdNode *node));
+DD_INLINE static void ddFixLimits ARGS((DdManager *unique));
+static void cuddOrderedInsert ARGS((DdNodePtr *root, DdNodePtr node));
+static DdNode * cuddOrderedThread ARGS((DdNode *root, DdNode *list));
+static void cuddRotateLeft ARGS((DdNodePtr *nodeP));
+static void cuddRotateRight ARGS((DdNodePtr *nodeP));
+static void cuddDoRebalance ARGS((DdNodePtr **stack, int stackN));
+static void ddPatchTree ARGS((DdManager *dd, MtrNode *treenode));
+#ifdef DD_DEBUG
+static int cuddCheckCollisionOrdering ARGS((DdManager *unique, int i, int j));
+#endif
+static void ddReportRefMess ARGS((DdManager *unique, int i, char *caller));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the next prime &gt;= p.]
+
+ Description []
+
+ SideEffects [None]
+
+******************************************************************************/
+unsigned int
+Cudd_Prime(
+ unsigned int p)
+{
+ int i,pn;
+
+ p--;
+ do {
+ p++;
+ if (p&1) {
+ pn = 1;
+ i = 3;
+ while ((unsigned) (i * i) <= p) {
+ if (p % i == 0) {
+ pn = 0;
+ break;
+ }
+ i += 2;
+ }
+ } else {
+ pn = 0;
+ }
+ } while (!pn);
+ return(p);
+
+} /* end of Cudd_Prime */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Fast storage allocation for DdNodes in the table.]
+
+ Description [Fast storage allocation for DdNodes in the table. The
+ first 4 bytes of a chunk contain a pointer to the next block; the
+ rest contains DD_MEM_CHUNK spaces for DdNodes. Returns a pointer to
+ a new node if successful; NULL is memory is full.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddDynamicAllocNode]
+
+******************************************************************************/
+DdNode *
+cuddAllocNode(
+ DdManager * unique)
+{
+ int i;
+ DdNodePtr *mem;
+ DdNode *list, *node;
+ extern void (*MMoutOfMemory)(long);
+ void (*saveHandler)(long);
+
+ if (unique->nextFree == NULL) { /* free list is empty */
+ /* Check for exceeded limits. */
+ if ((unique->keys - unique->dead) + (unique->keysZ - unique->deadZ) >
+ unique->maxLive) {
+ unique->errorCode = CUDD_TOO_MANY_NODES;
+ return(NULL);
+ }
+ if (unique->stash == NULL || unique->memused > unique->maxmemhard) {
+ (void) cuddGarbageCollect(unique,1);
+ mem = NULL;
+ }
+ if (unique->nextFree == NULL) {
+ if (unique->memused > unique->maxmemhard) {
+ unique->errorCode = CUDD_MAX_MEM_EXCEEDED;
+ return(NULL);
+ }
+ /* Try to allocate a new block. */
+ saveHandler = MMoutOfMemory;
+ MMoutOfMemory = Cudd_OutOfMem;
+ mem = (DdNodePtr *) ALLOC(DdNode,DD_MEM_CHUNK + 1);
+ MMoutOfMemory = saveHandler;
+ if (mem == NULL) {
+ /* No more memory: Try collecting garbage. If this succeeds,
+ ** we end up with mem still NULL, but unique->nextFree !=
+ ** NULL. */
+ if (cuddGarbageCollect(unique,1) == 0) {
+ /* Last resort: Free the memory stashed away, if there
+ ** any. If this succeeeds, mem != NULL and
+ ** unique->nextFree still NULL. */
+ if (unique->stash != NULL) {
+ FREE(unique->stash);
+ unique->stash = NULL;
+ /* Inhibit resizing of tables. */
+ cuddSlowTableGrowth(unique);
+ /* Now try again. */
+ mem = (DdNodePtr *) ALLOC(DdNode,DD_MEM_CHUNK + 1);
+ }
+ if (mem == NULL) {
+ /* Out of luck. Call the default handler to do
+ ** whatever it specifies for a failed malloc.
+ ** If this handler returns, then set error code,
+ ** print warning, and return. */
+ (*MMoutOfMemory)(sizeof(DdNode)*(DD_MEM_CHUNK + 1));
+ unique->errorCode = CUDD_MEMORY_OUT;
+#ifdef DD_VERBOSE
+ (void) fprintf(unique->err,
+ "cuddAllocNode: out of memory");
+ (void) fprintf(unique->err, "Memory in use = %ld\n",
+ unique->memused);
+#endif
+ return(NULL);
+ }
+ }
+ }
+ if (mem != NULL) { /* successful allocation; slice memory */
+ ptruint offset;
+ unique->memused += (DD_MEM_CHUNK + 1) * sizeof(DdNode);
+ mem[0] = (DdNodePtr) unique->memoryList;
+ unique->memoryList = mem;
+
+ /* Here we rely on the fact that a DdNode is as large
+ ** as 4 pointers. */
+ offset = (ptruint) mem & (sizeof(DdNode) - 1);
+ mem += (sizeof(DdNode) - offset) / sizeof(DdNodePtr);
+ assert(((ptruint) mem & (sizeof(DdNode) - 1)) == 0);
+ list = (DdNode *) mem;
+
+ i = 1;
+ do {
+ list[i - 1].next = &list[i];
+ } while (++i < DD_MEM_CHUNK);
+
+ list[DD_MEM_CHUNK-1].next = NULL;
+
+ unique->nextFree = &list[0];
+ }
+ }
+ }
+ unique->allocated++;
+ node = unique->nextFree;
+ unique->nextFree = node->next;
+ return(node);
+
+} /* end of cuddAllocNode */
+
+
+/**Function********************************************************************
+
+ Synopsis [Creates and initializes the unique table.]
+
+ Description [Creates and initializes the unique table. Returns a pointer
+ to the table if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Init cuddFreeTable]
+
+******************************************************************************/
+DdManager *
+cuddInitTable(
+ unsigned int numVars /* Initial number of BDD variables (and subtables) */,
+ unsigned int numVarsZ /* Initial number of ZDD variables (and subtables) */,
+ unsigned int numSlots /* Initial size of the BDD subtables */,
+ unsigned int looseUpTo /* Limit for fast table growth */)
+{
+ DdManager *unique = ALLOC(DdManager,1);
+ int i, j;
+ DdNodePtr *nodelist;
+ DdNode *sentinel;
+ unsigned int slots;
+ int shift;
+
+ if (unique == NULL) {
+ return(NULL);
+ }
+ sentinel = &(unique->sentinel);
+ sentinel->ref = 0;
+ sentinel->index = 0;
+ cuddT(sentinel) = NULL;
+ cuddE(sentinel) = NULL;
+ sentinel->next = NULL;
+ unique->epsilon = DD_EPSILON;
+ unique->maxGrowth = DD_MAX_REORDER_GROWTH;
+ unique->maxGrowthAlt = 2.0 * DD_MAX_REORDER_GROWTH;
+ unique->reordCycle = 0; /* do not use alternate threshold */
+ unique->size = numVars;
+ unique->sizeZ = numVarsZ;
+ unique->maxSize = ddMax(DD_DEFAULT_RESIZE, numVars);
+ unique->maxSizeZ = ddMax(DD_DEFAULT_RESIZE, numVarsZ);
+
+ /* Adjust the requested number of slots to a power of 2. */
+ slots = 8;
+ while (slots < numSlots) {
+ slots <<= 1;
+ }
+ unique->initSlots = slots;
+ shift = sizeof(int) * 8 - cuddComputeFloorLog2(slots);
+
+ unique->slots = (numVars + numVarsZ + 1) * slots;
+ unique->keys = 0;
+ unique->maxLive = ~0; /* very large number */
+ unique->keysZ = 0;
+ unique->dead = 0;
+ unique->deadZ = 0;
+ unique->gcFrac = DD_GC_FRAC_HI;
+ unique->minDead = (unsigned) (DD_GC_FRAC_HI * (double) unique->slots);
+ unique->looseUpTo = looseUpTo;
+ unique->gcEnabled = 1;
+ unique->allocated = 0;
+ unique->reclaimed = 0;
+ unique->subtables = ALLOC(DdSubtable,unique->maxSize);
+ if (unique->subtables == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ unique->subtableZ = ALLOC(DdSubtable,unique->maxSizeZ);
+ if (unique->subtableZ == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ unique->perm = ALLOC(int,unique->maxSize);
+ if (unique->perm == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ unique->invperm = ALLOC(int,unique->maxSize);
+ if (unique->invperm == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ unique->permZ = ALLOC(int,unique->maxSizeZ);
+ if (unique->permZ == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ unique->invpermZ = ALLOC(int,unique->maxSizeZ);
+ if (unique->invpermZ == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ unique->map = NULL;
+ unique->stack = ALLOC(DdNodePtr,ddMax(unique->maxSize,unique->maxSizeZ)+1);
+ if (unique->stack == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ unique->stack[0] = NULL; /* to suppress harmless UMR */
+
+#ifndef DD_NO_DEATH_ROW
+ unique->deathRowDepth = 1 << cuddComputeFloorLog2(unique->looseUpTo >> 2);
+ unique->deathRow = ALLOC(DdNodePtr,unique->deathRowDepth);
+ if (unique->deathRow == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (i = 0; i < unique->deathRowDepth; i++) {
+ unique->deathRow[i] = NULL;
+ }
+ unique->nextDead = 0;
+ unique->deadMask = unique->deathRowDepth - 1;
+#endif
+
+ for (i = 0; (unsigned) i < numVars; i++) {
+ unique->subtables[i].slots = slots;
+ unique->subtables[i].shift = shift;
+ unique->subtables[i].keys = 0;
+ unique->subtables[i].dead = 0;
+ unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
+ unique->subtables[i].bindVar = 0;
+ unique->subtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
+ unique->subtables[i].pairIndex = 0;
+ unique->subtables[i].varHandled = 0;
+ unique->subtables[i].varToBeGrouped = CUDD_LAZY_NONE;
+
+ nodelist = unique->subtables[i].nodelist = ALLOC(DdNodePtr,slots);
+ if (nodelist == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (j = 0; (unsigned) j < slots; j++) {
+ nodelist[j] = sentinel;
+ }
+ unique->perm[i] = i;
+ unique->invperm[i] = i;
+ }
+ for (i = 0; (unsigned) i < numVarsZ; i++) {
+ unique->subtableZ[i].slots = slots;
+ unique->subtableZ[i].shift = shift;
+ unique->subtableZ[i].keys = 0;
+ unique->subtableZ[i].dead = 0;
+ unique->subtableZ[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
+ nodelist = unique->subtableZ[i].nodelist = ALLOC(DdNodePtr,slots);
+ if (nodelist == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (j = 0; (unsigned) j < slots; j++) {
+ nodelist[j] = NULL;
+ }
+ unique->permZ[i] = i;
+ unique->invpermZ[i] = i;
+ }
+ unique->constants.slots = slots;
+ unique->constants.shift = shift;
+ unique->constants.keys = 0;
+ unique->constants.dead = 0;
+ unique->constants.maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
+ nodelist = unique->constants.nodelist = ALLOC(DdNodePtr,slots);
+ if (nodelist == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (j = 0; (unsigned) j < slots; j++) {
+ nodelist[j] = NULL;
+ }
+
+ unique->memoryList = NULL;
+ unique->nextFree = NULL;
+
+ unique->memused = sizeof(DdManager) + (unique->maxSize + unique->maxSizeZ)
+ * (sizeof(DdSubtable) + 2 * sizeof(int)) + (numVars + 1) *
+ slots * sizeof(DdNodePtr) +
+ (ddMax(unique->maxSize,unique->maxSizeZ) + 1) * sizeof(DdNodePtr);
+#ifndef DD_NO_DEATH_ROW
+ unique->memused += unique->deathRowDepth * sizeof(DdNodePtr);
+#endif
+
+ /* Initialize fields concerned with automatic dynamic reordering */
+ unique->reorderings = 0;
+ unique->autoDyn = 0; /* initially disabled */
+ unique->autoDynZ = 0; /* initially disabled */
+ unique->realign = 0; /* initially disabled */
+ unique->realignZ = 0; /* initially disabled */
+ unique->reordered = 0;
+ unique->autoMethod = CUDD_REORDER_SIFT;
+ unique->autoMethodZ = CUDD_REORDER_SIFT;
+ unique->nextDyn = DD_FIRST_REORDER;
+ unique->countDead = ~0;
+ unique->siftMaxVar = DD_SIFT_MAX_VAR;
+ unique->siftMaxSwap = DD_SIFT_MAX_SWAPS;
+ unique->tree = NULL;
+ unique->treeZ = NULL;
+ unique->groupcheck = CUDD_GROUP_CHECK7;
+ unique->recomb = DD_DEFAULT_RECOMB;
+ unique->symmviolation = 0;
+ unique->arcviolation = 0;
+ unique->populationSize = 0;
+ unique->numberXovers = 0;
+ unique->linear = NULL;
+ unique->linearSize = 0;
+
+ /* Initialize ZDD universe. */
+ unique->univ = (DdNodePtr *)NULL;
+
+ /* Initialize auxiliary fields. */
+ unique->localCaches = NULL;
+ unique->preGCHook = NULL;
+ unique->postGCHook = NULL;
+ unique->preReorderingHook = NULL;
+ unique->postReorderingHook = NULL;
+ unique->out = stdout;
+ unique->err = stderr;
+ unique->errorCode = CUDD_NO_ERROR;
+
+ /* Initialize statistical counters. */
+ unique->maxmemhard = (long) ((~ (unsigned long) 0) >> 1);
+ unique->garbageCollections = 0;
+ unique->GCTime = 0;
+ unique->reordTime = 0;
+#ifdef DD_STATS
+ unique->nodesDropped = 0;
+ unique->nodesFreed = 0;
+#endif
+ unique->peakLiveNodes = 0;
+#ifdef DD_UNIQUE_PROFILE
+ unique->uniqueLookUps = 0;
+ unique->uniqueLinks = 0;
+#endif
+#ifdef DD_COUNT
+ unique->recursiveCalls = 0;
+ unique->swapSteps = 0;
+#ifdef DD_STATS
+ unique->nextSample = 250000;
+#endif
+#endif
+
+ return(unique);
+
+} /* end of cuddInitTable */
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees the resources associated to a unique table.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [cuddInitTable]
+
+******************************************************************************/
+void
+cuddFreeTable(
+ DdManager * unique)
+{
+ DdNodePtr *next;
+ DdNodePtr *memlist = unique->memoryList;
+ int i;
+
+ if (unique->univ != NULL) cuddZddFreeUniv(unique);
+ while (memlist != NULL) {
+ next = (DdNodePtr *) memlist[0]; /* link to next block */
+ FREE(memlist);
+ memlist = next;
+ }
+ unique->nextFree = NULL;
+ unique->memoryList = NULL;
+
+ for (i = 0; i < unique->size; i++) {
+ FREE(unique->subtables[i].nodelist);
+ }
+ for (i = 0; i < unique->sizeZ; i++) {
+ FREE(unique->subtableZ[i].nodelist);
+ }
+ FREE(unique->constants.nodelist);
+ FREE(unique->subtables);
+ FREE(unique->subtableZ);
+ FREE(unique->acache);
+ FREE(unique->perm);
+ FREE(unique->permZ);
+ FREE(unique->invperm);
+ FREE(unique->invpermZ);
+ FREE(unique->vars);
+ if (unique->map != NULL) FREE(unique->map);
+ FREE(unique->stack);
+#ifndef DD_NO_DEATH_ROW
+ FREE(unique->deathRow);
+#endif
+ if (unique->tree != NULL) Mtr_FreeTree(unique->tree);
+ if (unique->treeZ != NULL) Mtr_FreeTree(unique->treeZ);
+ if (unique->linear != NULL) FREE(unique->linear);
+ while (unique->preGCHook != NULL)
+ Cudd_RemoveHook(unique,unique->preGCHook->f,CUDD_PRE_GC_HOOK);
+ while (unique->postGCHook != NULL)
+ Cudd_RemoveHook(unique,unique->postGCHook->f,CUDD_POST_GC_HOOK);
+ while (unique->preReorderingHook != NULL)
+ Cudd_RemoveHook(unique,unique->preReorderingHook->f,
+ CUDD_PRE_REORDERING_HOOK);
+ while (unique->postReorderingHook != NULL)
+ Cudd_RemoveHook(unique,unique->postReorderingHook->f,
+ CUDD_POST_REORDERING_HOOK);
+ FREE(unique);
+
+} /* end of cuddFreeTable */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs garbage collection on a unique table.]
+
+ Description [Performs garbage collection on a unique table.
+ If clearCache is 0, the cache is not cleared. This should only be
+ specified if the cache has been cleared right before calling
+ cuddGarbageCollect. (As in the case of dynamic reordering.)
+ Returns the total number of deleted nodes.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddGarbageCollectZdd]
+
+******************************************************************************/
+int
+cuddGarbageCollect(
+ DdManager * unique,
+ int clearCache)
+{
+ DdHook *hook;
+ DdCache *cache = unique->cache;
+ DdNode *sentinel = &(unique->sentinel);
+ DdNodePtr *nodelist;
+ int i, j, deleted, totalDeleted;
+ DdCache *c;
+ DdNode *node,*next;
+ DdNodePtr *lastP;
+ int slots;
+ long localTime;
+#ifndef DD_UNSORTED_FREE_LIST
+ DdNodePtr tree;
+#endif
+
+#ifndef DD_NO_DEATH_ROW
+ cuddClearDeathRow(unique);
+#endif
+
+ hook = unique->preGCHook;
+ while (hook != NULL) {
+ int res = (hook->f)(unique,"BDD",NULL);
+ if (res == 0) return(0);
+ hook = hook->next;
+ }
+
+ if (unique->dead == 0) {
+ hook = unique->postGCHook;
+ while (hook != NULL) {
+ int res = (hook->f)(unique,"BDD",NULL);
+ if (res == 0) return(0);
+ hook = hook->next;
+ }
+ return(0);
+ }
+
+ /* If many nodes are being reclaimed, we want to resize the tables
+ ** more aggressively, to reduce the frequency of garbage collection.
+ */
+ if (clearCache && unique->gcFrac == DD_GC_FRAC_LO &&
+ unique->slots <= unique->looseUpTo && unique->stash != NULL) {
+ unique->minDead = (unsigned) (DD_GC_FRAC_HI * (double) unique->slots);
+#ifdef DD_VERBOSE
+ (void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_HI);
+ (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
+#endif
+ unique->gcFrac = DD_GC_FRAC_HI;
+ return(0);
+ }
+
+ localTime = util_cpu_time();
+
+ unique->garbageCollections++;
+#ifdef DD_VERBOSE
+ (void) fprintf(unique->err,
+ "garbage collecting (%d dead out of %d, min %d)...",
+ unique->dead, unique->keys, unique->minDead);
+#endif
+
+ /* Remove references to garbage collected nodes from the cache. */
+ if (clearCache) {
+ slots = unique->cacheSlots;
+ for (i = 0; i < slots; i++) {
+ c = &cache[i];
+ if (c->data != NULL) {
+ if (cuddClean(c->f)->ref == 0 ||
+ cuddClean(c->g)->ref == 0 ||
+ (((ptruint)c->f & 0x2) && Cudd_Regular(c->h)->ref == 0) ||
+ (c->data != DD_NON_CONSTANT &&
+ Cudd_Regular(c->data)->ref == 0)) {
+ c->data = NULL;
+ unique->cachedeletions++;
+ }
+ }
+ }
+ cuddLocalCacheClearDead(unique);
+ }
+
+ /* Now return dead nodes to free list. Count them for sanity check. */
+ totalDeleted = 0;
+#ifndef DD_UNSORTED_FREE_LIST
+ tree = NULL;
+#endif
+
+ for (i = 0; i < unique->size; i++) {
+ if (unique->subtables[i].dead == 0) continue;
+ nodelist = unique->subtables[i].nodelist;
+
+ deleted = 0;
+ slots = unique->subtables[i].slots;
+ for (j = 0; j < slots; j++) {
+ lastP = &(nodelist[j]);
+ node = *lastP;
+ while (node != sentinel) {
+ next = node->next;
+ if (node->ref == 0) {
+ deleted++;
+#ifndef DD_UNSORTED_FREE_LIST
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ cuddOrderedInsert(&tree,node);
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+#else
+ cuddDeallocNode(unique,node);
+#endif
+ } else {
+ *lastP = node;
+ lastP = &(node->next);
+ }
+ node = next;
+ }
+ *lastP = sentinel;
+ }
+ if ((unsigned) deleted != unique->subtables[i].dead) {
+ ddReportRefMess(unique, i, "cuddGarbageCollect");
+ }
+ totalDeleted += deleted;
+ unique->subtables[i].keys -= deleted;
+ unique->subtables[i].dead = 0;
+ }
+ if (unique->constants.dead != 0) {
+ nodelist = unique->constants.nodelist;
+ deleted = 0;
+ slots = unique->constants.slots;
+ for (j = 0; j < slots; j++) {
+ lastP = &(nodelist[j]);
+ node = *lastP;
+ while (node != NULL) {
+ next = node->next;
+ if (node->ref == 0) {
+ deleted++;
+#ifndef DD_UNSORTED_FREE_LIST
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ cuddOrderedInsert(&tree,node);
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+#else
+ cuddDeallocNode(unique,node);
+#endif
+ } else {
+ *lastP = node;
+ lastP = &(node->next);
+ }
+ node = next;
+ }
+ *lastP = NULL;
+ }
+ if ((unsigned) deleted != unique->constants.dead) {
+ ddReportRefMess(unique, CUDD_CONST_INDEX, "cuddGarbageCollect");
+ }
+ totalDeleted += deleted;
+ unique->constants.keys -= deleted;
+ unique->constants.dead = 0;
+ }
+ if ((unsigned) totalDeleted != unique->dead) {
+ ddReportRefMess(unique, -1, "cuddGarbageCollect");
+ }
+ unique->keys -= totalDeleted;
+ unique->dead = 0;
+#ifdef DD_STATS
+ unique->nodesFreed += (double) totalDeleted;
+#endif
+
+#ifndef DD_UNSORTED_FREE_LIST
+ unique->nextFree = cuddOrderedThread(tree,unique->nextFree);
+#endif
+
+ unique->GCTime += util_cpu_time() - localTime;
+
+ hook = unique->postGCHook;
+ while (hook != NULL) {
+ int res = (hook->f)(unique,"BDD",NULL);
+ if (res == 0) return(0);
+ hook = hook->next;
+ }
+
+#ifdef DD_VERBOSE
+ (void) fprintf(unique->err," done\n");
+#endif
+
+ return(totalDeleted);
+
+} /* end of cuddGarbageCollect */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs garbage collection on a ZDD unique table.]
+
+ Description [Performs garbage collection on a ZDD unique table.
+ If clearCache is 0, the cache is not cleared. This should only be
+ specified if the cache has been cleared right before calling
+ cuddGarbageCollectZdd. (As in the case of dynamic reordering.)
+ Returns the total number of deleted nodes.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddGarbageCollect]
+
+******************************************************************************/
+int
+cuddGarbageCollectZdd(
+ DdManager * unique,
+ int clearCache)
+{
+ DdHook *hook;
+ DdCache *cache = unique->cache;
+ DdNodePtr *nodelist;
+ int i, j, deleted, totalDeleted;
+ DdCache *c;
+ DdNode *node,*next;
+ DdNodePtr *lastP;
+ int slots;
+ long localTime;
+#ifndef DD_UNSORTED_FREE_LIST
+ DdNodePtr tree;
+#endif
+
+ hook = unique->preGCHook;
+ while (hook != NULL) {
+ int res = (hook->f)(unique,"ZDD",NULL);
+ if (res == 0) return(0);
+ hook = hook->next;
+ }
+
+ if (unique->deadZ == 0) {
+ hook = unique->postGCHook;
+ while (hook != NULL) {
+ int res = (hook->f)(unique,"ZDD",NULL);
+ if (res == 0) return(0);
+ hook = hook->next;
+ }
+ return(0);
+ }
+
+ /* If many nodes are being reclaimed, we want to resize the tables
+ ** more aggressively, to reduce the frequency of garbage collection.
+ */
+ if (clearCache && unique->slots <= unique->looseUpTo) {
+ unique->minDead = (unsigned) (DD_GC_FRAC_HI * (double) unique->slots);
+#ifdef DD_VERBOSE
+ if (unique->gcFrac == DD_GC_FRAC_LO) {
+ (void) fprintf(unique->err,"GC fraction = %.2f\t",
+ DD_GC_FRAC_HI);
+ (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
+ }
+#endif
+ unique->gcFrac = DD_GC_FRAC_HI;
+ }
+
+ localTime = util_cpu_time();
+
+ unique->garbageCollections++;
+#ifdef DD_VERBOSE
+ (void) fprintf(unique->err,"garbage collecting (%d dead out of %d)...",
+ unique->deadZ,unique->keysZ);
+#endif
+
+ /* Remove references to garbage collected nodes from the cache. */
+ if (clearCache) {
+ slots = unique->cacheSlots;
+ for (i = 0; i < slots; i++) {
+ c = &cache[i];
+ if (c->data != NULL) {
+ if (cuddClean(c->f)->ref == 0 ||
+ cuddClean(c->g)->ref == 0 ||
+ (((ptruint)c->f & 0x2) && Cudd_Regular(c->h)->ref == 0) ||
+ (c->data != DD_NON_CONSTANT &&
+ Cudd_Regular(c->data)->ref == 0)) {
+ c->data = NULL;
+ unique->cachedeletions++;
+ }
+ }
+ }
+ }
+
+ /* Now return dead nodes to free list. Count them for sanity check. */
+ totalDeleted = 0;
+#ifndef DD_UNSORTED_FREE_LIST
+ tree = NULL;
+#endif
+
+ for (i = 0; i < unique->sizeZ; i++) {
+ if (unique->subtableZ[i].dead == 0) continue;
+ nodelist = unique->subtableZ[i].nodelist;
+
+ deleted = 0;
+ slots = unique->subtableZ[i].slots;
+ for (j = 0; j < slots; j++) {
+ lastP = &(nodelist[j]);
+ node = *lastP;
+ while (node != NULL) {
+ next = node->next;
+ if (node->ref == 0) {
+ deleted++;
+#ifndef DD_UNSORTED_FREE_LIST
+#ifdef __osf__
+#pragma pointer_size save
+#pragma pointer_size short
+#endif
+ cuddOrderedInsert(&tree,node);
+#ifdef __osf__
+#pragma pointer_size restore
+#endif
+#else
+ cuddDeallocNode(unique,node);
+#endif
+ } else {
+ *lastP = node;
+ lastP = &(node->next);
+ }
+ node = next;
+ }
+ *lastP = NULL;
+ }
+ if ((unsigned) deleted != unique->subtableZ[i].dead) {
+ ddReportRefMess(unique, i, "cuddGarbageCollectZdd");
+ }
+ totalDeleted += deleted;
+ unique->subtableZ[i].keys -= deleted;
+ unique->subtableZ[i].dead = 0;
+ }
+
+ /* No need to examine the constant table for ZDDs.
+ ** If we did we should be careful not to count whatever dead
+ ** nodes we found there among the dead ZDD nodes. */
+ if ((unsigned) totalDeleted != unique->deadZ) {
+ ddReportRefMess(unique, -1, "cuddGarbageCollectZdd");
+ }
+ unique->keysZ -= totalDeleted;
+ unique->deadZ = 0;
+#ifdef DD_STATS
+ unique->nodesFreed += (double) totalDeleted;
+#endif
+
+#ifndef DD_UNSORTED_FREE_LIST
+ unique->nextFree = cuddOrderedThread(tree,unique->nextFree);
+#endif
+
+ unique->GCTime += util_cpu_time() - localTime;
+
+ hook = unique->postGCHook;
+ while (hook != NULL) {
+ int res = (hook->f)(unique,"ZDD",NULL);
+ if (res == 0) return(0);
+ hook = hook->next;
+ }
+
+#ifdef DD_VERBOSE
+ (void) fprintf(unique->err," done\n");
+#endif
+
+ return(totalDeleted);
+
+} /* end of cuddGarbageCollectZdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Wrapper for cuddUniqueInterZdd.]
+
+ Description [Wrapper for cuddUniqueInterZdd, which applies the ZDD
+ reduction rule. Returns a pointer to the result node under normal
+ conditions; NULL if reordering occurred or memory was exhausted.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddUniqueInterZdd]
+
+******************************************************************************/
+DdNode *
+cuddZddGetNode(
+ DdManager * zdd,
+ int id,
+ DdNode * T,
+ DdNode * E)
+{
+ DdNode *node;
+
+ if (T == DD_ZERO(zdd))
+ return(E);
+ node = cuddUniqueInterZdd(zdd, id, T, E);
+ return(node);
+
+} /* end of cuddZddGetNode */
+
+
+/**Function********************************************************************
+
+ Synopsis [Wrapper for cuddUniqueInterZdd that is independent of variable
+ ordering.]
+
+ Description [Wrapper for cuddUniqueInterZdd that is independent of
+ variable ordering (IVO). This function does not require parameter
+ index to precede the indices of the top nodes of g and h in the
+ variable order. Returns a pointer to the result node under normal
+ conditions; NULL if reordering occurred or memory was exhausted.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddZddGetNode cuddZddIsop]
+
+******************************************************************************/
+DdNode *
+cuddZddGetNodeIVO(
+ DdManager * dd,
+ int index,
+ DdNode * g,
+ DdNode * h)
+{
+ DdNode *f, *r, *t;
+ DdNode *zdd_one = DD_ONE(dd);
+ DdNode *zdd_zero = DD_ZERO(dd);
+
+ f = cuddUniqueInterZdd(dd, index, zdd_one, zdd_zero);
+ if (f == NULL) {
+ return(NULL);
+ }
+ cuddRef(f);
+ t = cuddZddProduct(dd, f, g);
+ if (t == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f);
+ return(NULL);
+ }
+ cuddRef(t);
+ Cudd_RecursiveDerefZdd(dd, f);
+ r = cuddZddUnion(dd, t, h);
+ if (r == NULL) {
+ Cudd_RecursiveDerefZdd(dd, t);
+ return(NULL);
+ }
+ cuddRef(r);
+ Cudd_RecursiveDerefZdd(dd, t);
+
+ cuddDeref(r);
+ return(r);
+
+} /* end of cuddZddGetNodeIVO */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks the unique table for the existence of an internal node.]
+
+ Description [Checks the unique table for the existence of an internal
+ node. If it does not exist, it creates a new one. Does not
+ modify the reference count of whatever is returned. A newly created
+ internal node comes back with a reference count 0. For a newly
+ created node, increments the reference counts of what T and E point
+ to. Returns a pointer to the new node if successful; NULL if memory
+ is exhausted or if reordering took place.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddUniqueInterZdd]
+
+******************************************************************************/
+DdNode *
+cuddUniqueInter(
+ DdManager * unique,
+ int index,
+ DdNode * T,
+ DdNode * E)
+{
+ int pos;
+ unsigned int level;
+ int retval;
+ DdNodePtr *nodelist;
+ DdNode *looking;
+ DdNodePtr *previousP;
+ DdSubtable *subtable;
+ int gcNumber;
+
+#ifdef DD_UNIQUE_PROFILE
+ unique->uniqueLookUps++;
+#endif
+
+ if (index >= unique->size) {
+ if (!ddResizeTable(unique,index)) return(NULL);
+ }
+
+ level = unique->perm[index];
+ subtable = &(unique->subtables[level]);
+
+#ifdef DD_DEBUG
+ assert(level < (unsigned) cuddI(unique,T->index));
+ assert(level < (unsigned) cuddI(unique,Cudd_Regular(E)->index));
+#endif
+
+ pos = ddHash(T, E, subtable->shift);
+ nodelist = subtable->nodelist;
+ previousP = &(nodelist[pos]);
+ looking = *previousP;
+
+ while (T < cuddT(looking)) {
+ previousP = &(looking->next);
+ looking = *previousP;
+#ifdef DD_UNIQUE_PROFILE
+ unique->uniqueLinks++;
+#endif
+ }
+ while (T == cuddT(looking) && E < cuddE(looking)) {
+ previousP = &(looking->next);
+ looking = *previousP;
+#ifdef DD_UNIQUE_PROFILE
+ unique->uniqueLinks++;
+#endif
+ }
+ if (T == cuddT(looking) && E == cuddE(looking)) {
+ if (looking->ref == 0) {
+ cuddReclaim(unique,looking);
+ }
+ return(looking);
+ }
+
+ /* countDead is 0 if deads should be counted and ~0 if they should not. */
+ if (unique->autoDyn &&
+ unique->keys - (unique->dead & unique->countDead) >= unique->nextDyn) {
+#ifdef DD_DEBUG
+ retval = Cudd_DebugCheck(unique);
+ if (retval != 0) return(NULL);
+ retval = Cudd_CheckKeys(unique);
+ if (retval != 0) return(NULL);
+#endif
+ retval = Cudd_ReduceHeap(unique,unique->autoMethod,10); /* 10 = whatever */
+ if (retval == 0) unique->reordered = 2;
+#ifdef DD_DEBUG
+ retval = Cudd_DebugCheck(unique);
+ if (retval != 0) unique->reordered = 2;
+ retval = Cudd_CheckKeys(unique);
+ if (retval != 0) unique->reordered = 2;
+#endif
+ return(NULL);
+ }
+
+ if (subtable->keys > subtable->maxKeys) {
+ if (unique->gcEnabled &&
+ ((unique->dead > unique->minDead) ||
+ ((unique->dead > unique->minDead / 2) &&
+ (subtable->dead > subtable->keys * 0.95)))) { /* too many dead */
+ (void) cuddGarbageCollect(unique,1);
+ } else {
+ cuddRehash(unique,(int)level);
+ }
+ /* Update pointer to insertion point. In the case of rehashing,
+ ** the slot may have changed. In the case of garbage collection,
+ ** the predecessor may have been dead. */
+ pos = ddHash(T, E, subtable->shift);
+ nodelist = subtable->nodelist;
+ previousP = &(nodelist[pos]);
+ looking = *previousP;
+
+ while (T < cuddT(looking)) {
+ previousP = &(looking->next);
+ looking = *previousP;
+#ifdef DD_UNIQUE_PROFILE
+ unique->uniqueLinks++;
+#endif
+ }
+ while (T == cuddT(looking) && E < cuddE(looking)) {
+ previousP = &(looking->next);
+ looking = *previousP;
+#ifdef DD_UNIQUE_PROFILE
+ unique->uniqueLinks++;
+#endif
+ }
+ }
+
+ gcNumber = unique->garbageCollections;
+ looking = cuddAllocNode(unique);
+ if (looking == NULL) {
+ return(NULL);
+ }
+ unique->keys++;
+ subtable->keys++;
+
+ if (gcNumber != unique->garbageCollections) {
+ DdNode *looking2;
+ pos = ddHash(T, E, subtable->shift);
+ nodelist = subtable->nodelist;
+ previousP = &(nodelist[pos]);
+ looking2 = *previousP;
+
+ while (T < cuddT(looking2)) {
+ previousP = &(looking2->next);
+ looking2 = *previousP;
+#ifdef DD_UNIQUE_PROFILE
+ unique->uniqueLinks++;
+#endif
+ }
+ while (T == cuddT(looking2) && E < cuddE(looking2)) {
+ previousP = &(looking2->next);
+ looking2 = *previousP;
+#ifdef DD_UNIQUE_PROFILE
+ unique->uniqueLinks++;
+#endif
+ }
+ }
+ looking->ref = 0;
+ looking->index = index;
+ cuddT(looking) = T;
+ cuddE(looking) = E;
+ looking->next = *previousP;
+ *previousP = looking;
+ cuddSatInc(T->ref); /* we know T is a regular pointer */
+ cuddRef(E);
+
+#ifdef DD_DEBUG
+ cuddCheckCollisionOrdering(unique,level,pos);
+#endif
+
+ return(looking);
+
+} /* end of cuddUniqueInter */
+
+
+/**Function********************************************************************
+
+ Synopsis [Wrapper for cuddUniqueInter that is independent of variable
+ ordering.]
+
+ Description [Wrapper for cuddUniqueInter that is independent of
+ variable ordering (IVO). This function does not require parameter
+ index to precede the indices of the top nodes of T and E in the
+ variable order. Returns a pointer to the result node under normal
+ conditions; NULL if reordering occurred or memory was exhausted.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddUniqueInter Cudd_MakeBddFromZddCover]
+
+******************************************************************************/
+DdNode *
+cuddUniqueInterIVO(
+ DdManager * unique,
+ int index,
+ DdNode * T,
+ DdNode * E)
+{
+ DdNode *result;
+ DdNode *v;
+
+ v = cuddUniqueInter(unique, index, DD_ONE(unique),
+ Cudd_Not(DD_ONE(unique)));
+ if (v == NULL)
+ return(NULL);
+ cuddRef(v);
+ result = cuddBddIteRecur(unique, v, T, E);
+ Cudd_RecursiveDeref(unique, v);
+ return(result);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks the unique table for the existence of an internal
+ ZDD node.]
+
+ Description [Checks the unique table for the existence of an internal
+ ZDD node. If it does not exist, it creates a new one. Does not
+ modify the reference count of whatever is returned. A newly created
+ internal node comes back with a reference count 0. For a newly
+ created node, increments the reference counts of what T and E point
+ to. Returns a pointer to the new node if successful; NULL if memory
+ is exhausted or if reordering took place.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddUniqueInter]
+
+******************************************************************************/
+DdNode *
+cuddUniqueInterZdd(
+ DdManager * unique,
+ int index,
+ DdNode * T,
+ DdNode * E)
+{
+ int pos;
+ unsigned int level;
+ int retval;
+ DdNodePtr *nodelist;
+ DdNode *looking;
+ DdSubtable *subtable;
+
+#ifdef DD_UNIQUE_PROFILE
+ unique->uniqueLookUps++;
+#endif
+
+ if (index >= unique->sizeZ) {
+ if (!cuddResizeTableZdd(unique,index)) return(NULL);
+ }
+
+ level = unique->permZ[index];
+ subtable = &(unique->subtableZ[level]);
+
+#ifdef DD_DEBUG
+ assert(level < (unsigned) cuddIZ(unique,T->index));
+ assert(level < (unsigned) cuddIZ(unique,Cudd_Regular(E)->index));
+#endif
+
+ if (subtable->keys > subtable->maxKeys) {
+ if (unique->gcEnabled && ((unique->deadZ > unique->minDead) ||
+ (10 * subtable->dead > 9 * subtable->keys))) { /* too many dead */
+ (void) cuddGarbageCollectZdd(unique,1);
+ } else {
+ ddRehashZdd(unique,(int)level);
+ }
+ }
+
+ pos = ddHash(T, E, subtable->shift);
+ nodelist = subtable->nodelist;
+ looking = nodelist[pos];
+
+ while (looking != NULL) {
+ if (cuddT(looking) == T && cuddE(looking) == E) {
+ if (looking->ref == 0) {
+ cuddReclaimZdd(unique,looking);
+ }
+ return(looking);
+ }
+ looking = looking->next;
+#ifdef DD_UNIQUE_PROFILE
+ unique->uniqueLinks++;
+#endif
+ }
+
+ /* countDead is 0 if deads should be counted and ~0 if they should not. */
+ if (unique->autoDynZ &&
+ unique->keysZ - (unique->deadZ & unique->countDead) >= unique->nextDyn) {
+#ifdef DD_DEBUG
+ retval = Cudd_DebugCheck(unique);
+ if (retval != 0) return(NULL);
+ retval = Cudd_CheckKeys(unique);
+ if (retval != 0) return(NULL);
+#endif
+ retval = Cudd_zddReduceHeap(unique,unique->autoMethodZ,10); /* 10 = whatever */
+ if (retval == 0) unique->reordered = 2;
+#ifdef DD_DEBUG
+ retval = Cudd_DebugCheck(unique);
+ if (retval != 0) unique->reordered = 2;
+ retval = Cudd_CheckKeys(unique);
+ if (retval != 0) unique->reordered = 2;
+#endif
+ return(NULL);
+ }
+
+ unique->keysZ++;
+ subtable->keys++;
+
+ looking = cuddAllocNode(unique);
+ if (looking == NULL) return(NULL);
+ looking->ref = 0;
+ looking->index = index;
+ cuddT(looking) = T;
+ cuddE(looking) = E;
+ looking->next = nodelist[pos];
+ nodelist[pos] = looking;
+ cuddRef(T);
+ cuddRef(E);
+
+ return(looking);
+
+} /* end of cuddUniqueInterZdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks the unique table for the existence of a constant node.]
+
+ Description [Checks the unique table for the existence of a constant node.
+ If it does not exist, it creates a new one. Does not
+ modify the reference count of whatever is returned. A newly created
+ internal node comes back with a reference count 0. Returns a
+ pointer to the new node.]
+
+ SideEffects [None]
+
+******************************************************************************/
+DdNode *
+cuddUniqueConst(
+ DdManager * unique,
+ CUDD_VALUE_TYPE value)
+{
+ int pos;
+ DdNodePtr *nodelist;
+ DdNode *looking;
+ hack split;
+
+#ifdef DD_UNIQUE_PROFILE
+ unique->uniqueLookUps++;
+#endif
+
+ if (unique->constants.keys > unique->constants.maxKeys) {
+ if (unique->gcEnabled && ((unique->dead > unique->minDead) ||
+ (10 * unique->constants.dead > 9 * unique->constants.keys))) { /* too many dead */
+ (void) cuddGarbageCollect(unique,1);
+ } else {
+ cuddRehash(unique,CUDD_CONST_INDEX);
+ }
+ }
+
+ cuddAdjust(value); /* for the case of crippled infinities */
+
+ if (ddAbs(value) < unique->epsilon) {
+ value = 0.0;
+ }
+ split.value = value;
+
+ pos = ddHash(split.bits[0], split.bits[1], unique->constants.shift);
+ nodelist = unique->constants.nodelist;
+ looking = nodelist[pos];
+
+ /* Here we compare values both for equality and for difference less
+ * than epsilon. The first comparison is required when values are
+ * infinite, since Infinity - Infinity is NaN and NaN < X is 0 for
+ * every X.
+ */
+ while (looking != NULL) {
+ if (looking->type.value == value ||
+ ddEqualVal(looking->type.value,value,unique->epsilon)) {
+ if (looking->ref == 0) {
+ cuddReclaim(unique,looking);
+ }
+ return(looking);
+ }
+ looking = looking->next;
+#ifdef DD_UNIQUE_PROFILE
+ unique->uniqueLinks++;
+#endif
+ }
+
+ unique->keys++;
+ unique->constants.keys++;
+
+ looking = cuddAllocNode(unique);
+ if (looking == NULL) return(NULL);
+ looking->ref = 0;
+ looking->index = CUDD_CONST_INDEX;
+ looking->type.value = value;
+ looking->next = nodelist[pos];
+ nodelist[pos] = looking;
+
+ return(looking);
+
+} /* end of cuddUniqueConst */
+
+
+/**Function********************************************************************
+
+ Synopsis [Rehashes a unique subtable.]
+
+ Description [Doubles the size of a unique subtable and rehashes its
+ contents.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+cuddRehash(
+ DdManager * unique,
+ int i)
+{
+ unsigned int slots, oldslots;
+ int shift, oldshift;
+ int j, pos;
+ DdNodePtr *nodelist, *oldnodelist;
+ DdNode *node, *next;
+ DdNode *sentinel = &(unique->sentinel);
+ hack split;
+ extern void (*MMoutOfMemory)(long);
+ void (*saveHandler)(long);
+
+ if (unique->gcFrac == DD_GC_FRAC_HI && unique->slots > unique->looseUpTo) {
+ unique->gcFrac = DD_GC_FRAC_LO;
+ unique->minDead = (unsigned) (DD_GC_FRAC_LO * (double) unique->slots);
+#ifdef DD_VERBOSE
+ (void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_LO);
+ (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
+#endif
+ }
+
+ if (unique->gcFrac != DD_GC_FRAC_MIN && unique->memused > unique->maxmem) {
+ unique->gcFrac = DD_GC_FRAC_MIN;
+ unique->minDead = (unsigned) (DD_GC_FRAC_MIN * (double) unique->slots);
+#ifdef DD_VERBOSE
+ (void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_MIN);
+ (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
+#endif
+ cuddShrinkDeathRow(unique);
+ if (cuddGarbageCollect(unique,1) > 0) return;
+ }
+
+ if (i != CUDD_CONST_INDEX) {
+ oldslots = unique->subtables[i].slots;
+ oldshift = unique->subtables[i].shift;
+ oldnodelist = unique->subtables[i].nodelist;
+
+ /* Compute the new size of the subtable. */
+ slots = oldslots << 1;
+ shift = oldshift - 1;
+
+ saveHandler = MMoutOfMemory;
+ MMoutOfMemory = Cudd_OutOfMem;
+ nodelist = ALLOC(DdNodePtr, slots);
+ MMoutOfMemory = saveHandler;
+ if (nodelist == NULL) {
+ (void) fprintf(unique->err,
+ "Unable to resize subtable %d for lack of memory\n",
+ i);
+ /* Prevent frequent resizing attempts. */
+ (void) cuddGarbageCollect(unique,1);
+ if (unique->stash != NULL) {
+ FREE(unique->stash);
+ unique->stash = NULL;
+ /* Inhibit resizing of tables. */
+ cuddSlowTableGrowth(unique);
+ }
+ return;
+ }
+ unique->subtables[i].nodelist = nodelist;
+ unique->subtables[i].slots = slots;
+ unique->subtables[i].shift = shift;
+ unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
+
+ /* Move the nodes from the old table to the new table.
+ ** This code depends on the type of hash function.
+ ** It assumes that the effect of doubling the size of the table
+ ** is to retain one more bit of the 32-bit hash value.
+ ** The additional bit is the LSB. */
+ for (j = 0; (unsigned) j < oldslots; j++) {
+ DdNodePtr *evenP, *oddP;
+ node = oldnodelist[j];
+ evenP = &(nodelist[j<<1]);
+ oddP = &(nodelist[(j<<1)+1]);
+ while (node != sentinel) {
+ next = node->next;
+ pos = ddHash(cuddT(node), cuddE(node), shift);
+ if (pos & 1) {
+ *oddP = node;
+ oddP = &(node->next);
+ } else {
+ *evenP = node;
+ evenP = &(node->next);
+ }
+ node = next;
+ }
+ *evenP = *oddP = sentinel;
+ }
+ FREE(oldnodelist);
+
+#ifdef DD_VERBOSE
+ (void) fprintf(unique->err,
+ "rehashing layer %d: keys %d dead %d new size %d\n",
+ i, unique->subtables[i].keys,
+ unique->subtables[i].dead, slots);
+#endif
+ } else {
+ oldslots = unique->constants.slots;
+ oldshift = unique->constants.shift;
+ oldnodelist = unique->constants.nodelist;
+
+ /* The constant subtable is never subjected to reordering.
+ ** Therefore, when it is resized, it is because it has just
+ ** reached the maximum load. We can safely just double the size,
+ ** with no need for the loop we use for the other tables.
+ */
+ slots = oldslots << 1;
+ shift = oldshift - 1;
+ saveHandler = MMoutOfMemory;
+ MMoutOfMemory = Cudd_OutOfMem;
+ nodelist = ALLOC(DdNodePtr, slots);
+ MMoutOfMemory = saveHandler;
+ if (nodelist == NULL) {
+ int j;
+ (void) fprintf(unique->err,
+ "Unable to resize constant subtable for lack of memory\n");
+ (void) cuddGarbageCollect(unique,1);
+ for (j = 0; j < unique->size; j++) {
+ unique->subtables[j].maxKeys <<= 1;
+ }
+ unique->constants.maxKeys <<= 1;
+ return;
+ }
+ unique->constants.slots = slots;
+ unique->constants.shift = shift;
+ unique->constants.maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
+ unique->constants.nodelist = nodelist;
+ for (j = 0; (unsigned) j < slots; j++) {
+ nodelist[j] = NULL;
+ }
+ for (j = 0; (unsigned) j < oldslots; j++) {
+ node = oldnodelist[j];
+ while (node != NULL) {
+ next = node->next;
+ split.value = cuddV(node);
+ pos = ddHash(split.bits[0], split.bits[1], shift);
+ node->next = nodelist[pos];
+ nodelist[pos] = node;
+ node = next;
+ }
+ }
+ FREE(oldnodelist);
+
+#ifdef DD_VERBOSE
+ (void) fprintf(unique->err,
+ "rehashing constants: keys %d dead %d new size %d\n",
+ unique->constants.keys,unique->constants.dead,slots);
+#endif
+ }
+
+ /* Update global data */
+
+ unique->memused += (slots - oldslots) * sizeof(DdNodePtr);
+ unique->slots += (slots - oldslots);
+ ddFixLimits(unique);
+
+} /* end of cuddRehash */
+
+
+/**Function********************************************************************
+
+ Synopsis [Shrinks a subtable.]
+
+ Description [Shrinks a subtable.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddRehash]
+
+******************************************************************************/
+void
+cuddShrinkSubtable(
+ DdManager *unique,
+ int i)
+{
+ int j;
+ int shift, posn;
+ DdNodePtr *nodelist, *oldnodelist;
+ DdNode *node, *next;
+ DdNode *sentinel = &(unique->sentinel);
+ unsigned int slots, oldslots;
+ extern void (*MMoutOfMemory)(long);
+ void (*saveHandler)(long);
+
+ oldnodelist = unique->subtables[i].nodelist;
+ oldslots = unique->subtables[i].slots;
+ slots = oldslots >> 1;
+ saveHandler = MMoutOfMemory;
+ MMoutOfMemory = Cudd_OutOfMem;
+ nodelist = ALLOC(DdNodePtr, slots);
+ MMoutOfMemory = saveHandler;
+ if (nodelist == NULL) {
+ return;
+ }
+ unique->subtables[i].nodelist = nodelist;
+ unique->subtables[i].slots = slots;
+ unique->subtables[i].shift++;
+ unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
+#ifdef DD_VERBOSE
+ (void) fprintf(unique->err,
+ "shrunk layer %d (%d keys) from %d to %d slots\n",
+ i, unique->subtables[i].keys, oldslots, slots);
+#endif
+
+ for (j = 0; (unsigned) j < slots; j++) {
+ nodelist[j] = sentinel;
+ }
+ shift = unique->subtables[i].shift;
+ for (j = 0; (unsigned) j < oldslots; j++) {
+ node = oldnodelist[j];
+ while (node != sentinel) {
+ DdNode *looking, *T, *E;
+ DdNodePtr *previousP;
+ next = node->next;
+ posn = ddHash(cuddT(node), cuddE(node), shift);
+ previousP = &(nodelist[posn]);
+ looking = *previousP;
+ T = cuddT(node);
+ E = cuddE(node);
+ while (T < cuddT(looking)) {
+ previousP = &(looking->next);
+ looking = *previousP;
+#ifdef DD_UNIQUE_PROFILE
+ unique->uniqueLinks++;
+#endif
+ }
+ while (T == cuddT(looking) && E < cuddE(looking)) {
+ previousP = &(looking->next);
+ looking = *previousP;
+#ifdef DD_UNIQUE_PROFILE
+ unique->uniqueLinks++;
+#endif
+ }
+ node->next = *previousP;
+ *previousP = node;
+ node = next;
+ }
+ }
+ FREE(oldnodelist);
+
+ unique->memused += ((long) slots - (long) oldslots) * sizeof(DdNode *);
+ unique->slots += slots - oldslots;
+ unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots);
+ unique->cacheSlack = (int)
+ ddMin(unique->maxCacheHard,DD_MAX_CACHE_TO_SLOTS_RATIO * unique->slots)
+ - 2 * (int) unique->cacheSlots;
+
+} /* end of cuddShrinkSubtable */
+
+
+/**Function********************************************************************
+
+ Synopsis [Inserts n new subtables in a unique table at level.]
+
+ Description [Inserts n new subtables in a unique table at level.
+ The number n should be positive, and level should be an existing level.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddDestroySubtables]
+
+******************************************************************************/
+int
+cuddInsertSubtables(
+ DdManager * unique,
+ int n,
+ int level)
+{
+ DdSubtable *newsubtables;
+ DdNodePtr *newnodelist;
+ DdNodePtr *newvars;
+ DdNode *sentinel = &(unique->sentinel);
+ int oldsize,newsize;
+ int i,j,index,reorderSave;
+ unsigned int numSlots = unique->initSlots;
+ int *newperm, *newinvperm, *newmap;
+ DdNode *one, *zero;
+
+#ifdef DD_DEBUG
+ assert(n > 0 && level < unique->size);
+#endif
+
+ oldsize = unique->size;
+ /* Easy case: there is still room in the current table. */
+ if (oldsize + n <= unique->maxSize) {
+ /* Shift the tables at and below level. */
+ for (i = oldsize - 1; i >= level; i--) {
+ unique->subtables[i+n].slots = unique->subtables[i].slots;
+ unique->subtables[i+n].shift = unique->subtables[i].shift;
+ unique->subtables[i+n].keys = unique->subtables[i].keys;
+ unique->subtables[i+n].maxKeys = unique->subtables[i].maxKeys;
+ unique->subtables[i+n].dead = unique->subtables[i].dead;
+ unique->subtables[i+n].nodelist = unique->subtables[i].nodelist;
+ unique->subtables[i+n].bindVar = unique->subtables[i].bindVar;
+ unique->subtables[i+n].varType = unique->subtables[i].varType;
+ unique->subtables[i+n].pairIndex = unique->subtables[i].pairIndex;
+ unique->subtables[i+n].varHandled = unique->subtables[i].varHandled;
+ unique->subtables[i+n].varToBeGrouped =
+ unique->subtables[i].varToBeGrouped;
+
+ index = unique->invperm[i];
+ unique->invperm[i+n] = index;
+ unique->perm[index] += n;
+ }
+ /* Create new subtables. */
+ for (i = 0; i < n; i++) {
+ unique->subtables[level+i].slots = numSlots;
+ unique->subtables[level+i].shift = sizeof(int) * 8 -
+ cuddComputeFloorLog2(numSlots);
+ unique->subtables[level+i].keys = 0;
+ unique->subtables[level+i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
+ unique->subtables[level+i].dead = 0;
+ unique->subtables[level+i].bindVar = 0;
+ unique->subtables[level+i].varType = CUDD_VAR_PRIMARY_INPUT;
+ unique->subtables[level+i].pairIndex = 0;
+ unique->subtables[level+i].varHandled = 0;
+ unique->subtables[level+i].varToBeGrouped = CUDD_LAZY_NONE;
+
+ unique->perm[oldsize+i] = level + i;
+ unique->invperm[level+i] = oldsize + i;
+ newnodelist = unique->subtables[level+i].nodelist =
+ ALLOC(DdNodePtr, numSlots);
+ if (newnodelist == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (j = 0; j < numSlots; j++) {
+ newnodelist[j] = sentinel;
+ }
+ }
+ if (unique->map != NULL) {
+ for (i = 0; i < n; i++) {
+ unique->map[oldsize+i] = oldsize + i;
+ }
+ }
+ } else {
+ /* The current table is too small: we need to allocate a new,
+ ** larger one; move all old subtables, and initialize the new
+ ** subtables.
+ */
+ newsize = oldsize + n + DD_DEFAULT_RESIZE;
+#ifdef DD_VERBOSE
+ (void) fprintf(unique->err,
+ "Increasing the table size from %d to %d\n",
+ unique->maxSize, newsize);
+#endif
+ /* Allocate memory for new arrays (except nodelists). */
+ newsubtables = ALLOC(DdSubtable,newsize);
+ if (newsubtables == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ newvars = ALLOC(DdNodePtr,newsize);
+ if (newvars == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ FREE(newsubtables);
+ return(0);
+ }
+ newperm = ALLOC(int,newsize);
+ if (newperm == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ FREE(newsubtables);
+ FREE(newvars);
+ return(0);
+ }
+ newinvperm = ALLOC(int,newsize);
+ if (newinvperm == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ FREE(newsubtables);
+ FREE(newvars);
+ FREE(newperm);
+ return(0);
+ }
+ if (unique->map != NULL) {
+ newmap = ALLOC(int,newsize);
+ if (newmap == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ FREE(newsubtables);
+ FREE(newvars);
+ FREE(newperm);
+ FREE(newinvperm);
+ return(0);
+ }
+ unique->memused += (newsize - unique->maxSize) * sizeof(int);
+ }
+ unique->memused += (newsize - unique->maxSize) * ((numSlots+1) *
+ sizeof(DdNode *) + 2 * sizeof(int) + sizeof(DdSubtable));
+ /* Copy levels before insertion points from old tables. */
+ for (i = 0; i < level; i++) {
+ newsubtables[i].slots = unique->subtables[i].slots;
+ newsubtables[i].shift = unique->subtables[i].shift;
+ newsubtables[i].keys = unique->subtables[i].keys;
+ newsubtables[i].maxKeys = unique->subtables[i].maxKeys;
+ newsubtables[i].dead = unique->subtables[i].dead;
+ newsubtables[i].nodelist = unique->subtables[i].nodelist;
+ newsubtables[i].bindVar = unique->subtables[i].bindVar;
+ newsubtables[i].varType = unique->subtables[i].varType;
+ newsubtables[i].pairIndex = unique->subtables[i].pairIndex;
+ newsubtables[i].varHandled = unique->subtables[i].varHandled;
+ newsubtables[i].varToBeGrouped = unique->subtables[i].varToBeGrouped;
+
+ newvars[i] = unique->vars[i];
+ newperm[i] = unique->perm[i];
+ newinvperm[i] = unique->invperm[i];
+ }
+ /* Finish initializing permutation for new table to old one. */
+ for (i = level; i < oldsize; i++) {
+ newperm[i] = unique->perm[i];
+ }
+ /* Initialize new levels. */
+ for (i = level; i < level + n; i++) {
+ newsubtables[i].slots = numSlots;
+ newsubtables[i].shift = sizeof(int) * 8 -
+ cuddComputeFloorLog2(numSlots);
+ newsubtables[i].keys = 0;
+ newsubtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
+ newsubtables[i].dead = 0;
+ newsubtables[i].bindVar = 0;
+ newsubtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
+ newsubtables[i].pairIndex = 0;
+ newsubtables[i].varHandled = 0;
+ newsubtables[i].varToBeGrouped = CUDD_LAZY_NONE;
+
+ newperm[oldsize + i - level] = i;
+ newinvperm[i] = oldsize + i - level;
+ newnodelist = newsubtables[i].nodelist = ALLOC(DdNodePtr, numSlots);
+ if (newnodelist == NULL) {
+ /* We are going to leak some memory. We should clean up. */
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (j = 0; j < numSlots; j++) {
+ newnodelist[j] = sentinel;
+ }
+ }
+ /* Copy the old tables for levels past the insertion point. */
+ for (i = level; i < oldsize; i++) {
+ newsubtables[i+n].slots = unique->subtables[i].slots;
+ newsubtables[i+n].shift = unique->subtables[i].shift;
+ newsubtables[i+n].keys = unique->subtables[i].keys;
+ newsubtables[i+n].maxKeys = unique->subtables[i].maxKeys;
+ newsubtables[i+n].dead = unique->subtables[i].dead;
+ newsubtables[i+n].nodelist = unique->subtables[i].nodelist;
+ newsubtables[i+n].bindVar = unique->subtables[i].bindVar;
+ newsubtables[i+n].varType = unique->subtables[i].varType;
+ newsubtables[i+n].pairIndex = unique->subtables[i].pairIndex;
+ newsubtables[i+n].varHandled = unique->subtables[i].varHandled;
+ newsubtables[i+n].varToBeGrouped =
+ unique->subtables[i].varToBeGrouped;
+
+ newvars[i] = unique->vars[i];
+ index = unique->invperm[i];
+ newinvperm[i+n] = index;
+ newperm[index] += n;
+ }
+ /* Update the map. */
+ if (unique->map != NULL) {
+ for (i = 0; i < oldsize; i++) {
+ newmap[i] = unique->map[i];
+ }
+ for (i = oldsize; i < oldsize + n; i++) {
+ newmap[i] = i;
+ }
+ FREE(unique->map);
+ unique->map = newmap;
+ }
+ /* Install the new tables and free the old ones. */
+ FREE(unique->subtables);
+ unique->subtables = newsubtables;
+ unique->maxSize = newsize;
+ FREE(unique->vars);
+ unique->vars = newvars;
+ FREE(unique->perm);
+ unique->perm = newperm;
+ FREE(unique->invperm);
+ unique->invperm = newinvperm;
+ /* Update the stack for iterative procedures. */
+ if (newsize > unique->maxSizeZ) {
+ FREE(unique->stack);
+ unique->stack = ALLOC(DdNodePtr,newsize + 1);
+ if (unique->stack == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ unique->stack[0] = NULL; /* to suppress harmless UMR */
+ unique->memused +=
+ (newsize - ddMax(unique->maxSize,unique->maxSizeZ))
+ * sizeof(DdNode *);
+ }
+ }
+ /* Update manager parameters to account for the new subtables. */
+ unique->slots += n * numSlots;
+ ddFixLimits(unique);
+ unique->size += n;
+
+ /* Now that the table is in a coherent state, create the new
+ ** projection functions. We need to temporarily disable reordering,
+ ** because we cannot reorder without projection functions in place.
+ **/
+ one = unique->one;
+ zero = Cudd_Not(one);
+
+ reorderSave = unique->autoDyn;
+ unique->autoDyn = 0;
+ for (i = oldsize; i < oldsize + n; i++) {
+ unique->vars[i] = cuddUniqueInter(unique,i,one,zero);
+ if (unique->vars[i] == NULL) {
+ unique->autoDyn = reorderSave;
+ /* Shift everything back so table remains coherent. */
+ for (j = oldsize; j < i; j++) {
+ Cudd_IterDerefBdd(unique,unique->vars[j]);
+ cuddDeallocNode(unique,unique->vars[j]);
+ unique->vars[j] = NULL;
+ }
+ for (j = level; j < oldsize; j++) {
+ unique->subtables[j].slots = unique->subtables[j+n].slots;
+ unique->subtables[j].slots = unique->subtables[j+n].slots;
+ unique->subtables[j].shift = unique->subtables[j+n].shift;
+ unique->subtables[j].keys = unique->subtables[j+n].keys;
+ unique->subtables[j].maxKeys =
+ unique->subtables[j+n].maxKeys;
+ unique->subtables[j].dead = unique->subtables[j+n].dead;
+ FREE(unique->subtables[j].nodelist);
+ unique->subtables[j].nodelist =
+ unique->subtables[j+n].nodelist;
+ unique->subtables[j+n].nodelist = NULL;
+ unique->subtables[j].bindVar =
+ unique->subtables[j+n].bindVar;
+ unique->subtables[j].varType =
+ unique->subtables[j+n].varType;
+ unique->subtables[j].pairIndex =
+ unique->subtables[j+n].pairIndex;
+ unique->subtables[j].varHandled =
+ unique->subtables[j+n].varHandled;
+ unique->subtables[j].varToBeGrouped =
+ unique->subtables[j+n].varToBeGrouped;
+ index = unique->invperm[j+n];
+ unique->invperm[j] = index;
+ unique->perm[index] -= n;
+ }
+ unique->size = oldsize;
+ unique->slots -= n * numSlots;
+ ddFixLimits(unique);
+ (void) Cudd_DebugCheck(unique);
+ return(0);
+ }
+ cuddRef(unique->vars[i]);
+ }
+ if (unique->tree != NULL) {
+ unique->tree->size += n;
+ unique->tree->index = unique->invperm[0];
+ ddPatchTree(unique,unique->tree);
+ }
+ unique->autoDyn = reorderSave;
+
+ return(1);
+
+} /* end of cuddInsertSubtables */
+
+
+/**Function********************************************************************
+
+ Synopsis [Destroys the n most recently created subtables in a unique table.]
+
+ Description [Destroys the n most recently created subtables in a unique
+ table. n should be positive. The subtables should not contain any live
+ nodes, except the (isolated) projection function. The projection
+ functions are freed. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [The variable map used for fast variable substitution is
+ destroyed if it exists. In this case the cache is also cleared.]
+
+ SeeAlso [cuddInsertSubtables Cudd_SetVarMap]
+
+******************************************************************************/
+int
+cuddDestroySubtables(
+ DdManager * unique,
+ int n)
+{
+ DdSubtable *subtables;
+ DdNodePtr *nodelist;
+ DdNodePtr *vars;
+ int firstIndex, lastIndex;
+ int index, level, newlevel;
+ int lowestLevel;
+ int shift;
+ int found;
+
+ /* Sanity check and set up. */
+ if (n <= 0) return(0);
+ if (n > unique->size) n = unique->size;
+
+ subtables = unique->subtables;
+ vars = unique->vars;
+ firstIndex = unique->size - n;
+ lastIndex = unique->size;
+
+ /* Check for nodes labeled by the variables being destroyed
+ ** that may still be in use. It is allowed to destroy a variable
+ ** only if there are no such nodes. Also, find the lowest level
+ ** among the variables being destroyed. This will make further
+ ** processing more efficient.
+ */
+ lowestLevel = unique->size;
+ for (index = firstIndex; index < lastIndex; index++) {
+ level = unique->perm[index];
+ if (level < lowestLevel) lowestLevel = level;
+ nodelist = subtables[level].nodelist;
+ if (subtables[level].keys - subtables[level].dead != 1) return(0);
+ /* The projection function should be isolated. If the ref count
+ ** is 1, everything is OK. If the ref count is saturated, then
+ ** we need to make sure that there are no nodes pointing to it.
+ ** As for the external references, we assume the application is
+ ** responsible for them.
+ */
+ if (vars[index]->ref != 1) {
+ if (vars[index]->ref != DD_MAXREF) return(0);
+ found = cuddFindParent(unique,vars[index]);
+ if (found) {
+ return(0);
+ } else {
+ vars[index]->ref = 1;
+ }
+ }
+ Cudd_RecursiveDeref(unique,vars[index]);
+ }
+
+ /* Collect garbage, because we cannot afford having dead nodes pointing
+ ** to the dead nodes in the subtables being destroyed.
+ */
+ (void) cuddGarbageCollect(unique,1);
+
+ /* Here we know we can destroy our subtables. */
+ for (index = firstIndex; index < lastIndex; index++) {
+ level = unique->perm[index];
+ nodelist = subtables[level].nodelist;
+#ifdef DD_DEBUG
+ assert(subtables[level].keys == 0);
+#endif
+ FREE(nodelist);
+ unique->memused -= sizeof(DdNodePtr) * subtables[level].slots;
+ unique->slots -= subtables[level].slots;
+ unique->dead -= subtables[level].dead;
+ }
+
+ /* Here all subtables to be destroyed have their keys field == 0 and
+ ** their hash tables have been freed.
+ ** We now scan the subtables from level lowestLevel + 1 to level size - 1,
+ ** shifting the subtables as required. We keep a running count of
+ ** how many subtables have been moved, so that we know by how many
+ ** positions each subtable should be shifted.
+ */
+ shift = 1;
+ for (level = lowestLevel + 1; level < unique->size; level++) {
+ if (subtables[level].keys == 0) {
+ shift++;
+ continue;
+ }
+ newlevel = level - shift;
+ subtables[newlevel].slots = subtables[level].slots;
+ subtables[newlevel].shift = subtables[level].shift;
+ subtables[newlevel].keys = subtables[level].keys;
+ subtables[newlevel].maxKeys = subtables[level].maxKeys;
+ subtables[newlevel].dead = subtables[level].dead;
+ subtables[newlevel].nodelist = subtables[level].nodelist;
+ index = unique->invperm[level];
+ unique->perm[index] = newlevel;
+ unique->invperm[newlevel] = index;
+ subtables[newlevel].bindVar = subtables[level].bindVar;
+ subtables[newlevel].varType = subtables[level].varType;
+ subtables[newlevel].pairIndex = subtables[level].pairIndex;
+ subtables[newlevel].varHandled = subtables[level].varHandled;
+ subtables[newlevel].varToBeGrouped = subtables[level].varToBeGrouped;
+ }
+ /* Destroy the map. If a surviving variable is
+ ** mapped to a dying variable, and the map were used again,
+ ** an out-of-bounds access to unique->vars would result. */
+ if (unique->map != NULL) {
+ cuddCacheFlush(unique);
+ FREE(unique->map);
+ unique->map = NULL;
+ }
+
+ unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots);
+ unique->size -= n;
+
+ return(1);
+
+} /* end of cuddDestroySubtables */
+
+
+/**Function********************************************************************
+
+ Synopsis [Increases the number of ZDD subtables in a unique table so
+ that it meets or exceeds index.]
+
+ Description [Increases the number of ZDD subtables in a unique table so
+ that it meets or exceeds index. When new ZDD variables are created, it
+ is possible to preserve the functions unchanged, or it is possible to
+ preserve the covers unchanged, but not both. cuddResizeTableZdd preserves
+ the covers. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [ddResizeTable]
+
+******************************************************************************/
+int
+cuddResizeTableZdd(
+ DdManager * unique,
+ int index)
+{
+ DdSubtable *newsubtables;
+ DdNodePtr *newnodelist;
+ int oldsize,newsize;
+ int i,j,reorderSave;
+ unsigned int numSlots = unique->initSlots;
+ int *newperm, *newinvperm;
+ DdNode *one, *zero;
+
+ oldsize = unique->sizeZ;
+ /* Easy case: there is still room in the current table. */
+ if (index < unique->maxSizeZ) {
+ for (i = oldsize; i <= index; i++) {
+ unique->subtableZ[i].slots = numSlots;
+ unique->subtableZ[i].shift = sizeof(int) * 8 -
+ cuddComputeFloorLog2(numSlots);
+ unique->subtableZ[i].keys = 0;
+ unique->subtableZ[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
+ unique->subtableZ[i].dead = 0;
+ unique->permZ[i] = i;
+ unique->invpermZ[i] = i;
+ newnodelist = unique->subtableZ[i].nodelist =
+ ALLOC(DdNodePtr, numSlots);
+ if (newnodelist == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (j = 0; j < numSlots; j++) {
+ newnodelist[j] = NULL;
+ }
+ }
+ } else {
+ /* The current table is too small: we need to allocate a new,
+ ** larger one; move all old subtables, and initialize the new
+ ** subtables up to index included.
+ */
+ newsize = index + DD_DEFAULT_RESIZE;
+#ifdef DD_VERBOSE
+ (void) fprintf(unique->err,
+ "Increasing the ZDD table size from %d to %d\n",
+ unique->maxSizeZ, newsize);
+#endif
+ newsubtables = ALLOC(DdSubtable,newsize);
+ if (newsubtables == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ newperm = ALLOC(int,newsize);
+ if (newperm == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ newinvperm = ALLOC(int,newsize);
+ if (newinvperm == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ unique->memused += (newsize - unique->maxSizeZ) * ((numSlots+1) *
+ sizeof(DdNode *) + 2 * sizeof(int) + sizeof(DdSubtable));
+ if (newsize > unique->maxSize) {
+ FREE(unique->stack);
+ unique->stack = ALLOC(DdNodePtr,newsize + 1);
+ if (unique->stack == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ unique->stack[0] = NULL; /* to suppress harmless UMR */
+ unique->memused +=
+ (newsize - ddMax(unique->maxSize,unique->maxSizeZ))
+ * sizeof(DdNode *);
+ }
+ for (i = 0; i < oldsize; i++) {
+ newsubtables[i].slots = unique->subtableZ[i].slots;
+ newsubtables[i].shift = unique->subtableZ[i].shift;
+ newsubtables[i].keys = unique->subtableZ[i].keys;
+ newsubtables[i].maxKeys = unique->subtableZ[i].maxKeys;
+ newsubtables[i].dead = unique->subtableZ[i].dead;
+ newsubtables[i].nodelist = unique->subtableZ[i].nodelist;
+ newperm[i] = unique->permZ[i];
+ newinvperm[i] = unique->invpermZ[i];
+ }
+ for (i = oldsize; i <= index; i++) {
+ newsubtables[i].slots = numSlots;
+ newsubtables[i].shift = sizeof(int) * 8 -
+ cuddComputeFloorLog2(numSlots);
+ newsubtables[i].keys = 0;
+ newsubtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
+ newsubtables[i].dead = 0;
+ newperm[i] = i;
+ newinvperm[i] = i;
+ newnodelist = newsubtables[i].nodelist = ALLOC(DdNodePtr, numSlots);
+ if (newnodelist == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (j = 0; j < numSlots; j++) {
+ newnodelist[j] = NULL;
+ }
+ }
+ FREE(unique->subtableZ);
+ unique->subtableZ = newsubtables;
+ unique->maxSizeZ = newsize;
+ FREE(unique->permZ);
+ unique->permZ = newperm;
+ FREE(unique->invpermZ);
+ unique->invpermZ = newinvperm;
+ }
+ unique->slots += (index + 1 - unique->sizeZ) * numSlots;
+ ddFixLimits(unique);
+ unique->sizeZ = index + 1;
+
+ /* Now that the table is in a coherent state, update the ZDD
+ ** universe. We need to temporarily disable reordering,
+ ** because we cannot reorder without universe in place.
+ */
+ one = unique->one;
+ zero = unique->zero;
+
+ reorderSave = unique->autoDynZ;
+ unique->autoDynZ = 0;
+ cuddZddFreeUniv(unique);
+ if (!cuddZddInitUniv(unique)) {
+ unique->autoDynZ = reorderSave;
+ return(0);
+ }
+ unique->autoDynZ = reorderSave;
+
+ return(1);
+
+} /* end of cuddResizeTableZdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Adjusts parameters of a table to slow down its growth.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+cuddSlowTableGrowth(
+ DdManager *unique)
+{
+ int i;
+
+ unique->maxCacheHard = unique->cacheSlots - 1;
+ unique->cacheSlack = -(unique->cacheSlots + 1);
+ for (i = 0; i < unique->size; i++) {
+ unique->subtables[i].maxKeys <<= 2;
+ }
+ unique->gcFrac = DD_GC_FRAC_MIN;
+ unique->minDead = (unsigned) (DD_GC_FRAC_MIN * (double) unique->slots);
+ cuddShrinkDeathRow(unique);
+ (void) fprintf(unique->err,"Slowing down table growth: ");
+ (void) fprintf(unique->err,"GC fraction = %.2f\t", unique->gcFrac);
+ (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
+
+} /* end of cuddSlowTableGrowth */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Rehashes a ZDD unique subtable.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [cuddRehash]
+
+******************************************************************************/
+static void
+ddRehashZdd(
+ DdManager * unique,
+ int i)
+{
+ unsigned int slots, oldslots;
+ int shift, oldshift;
+ int j, pos;
+ DdNodePtr *nodelist, *oldnodelist;
+ DdNode *node, *next;
+ extern void (*MMoutOfMemory)(long);
+ void (*saveHandler)(long);
+
+ if (unique->slots > unique->looseUpTo) {
+ unique->minDead = (unsigned) (DD_GC_FRAC_LO * (double) unique->slots);
+#ifdef DD_VERBOSE
+ if (unique->gcFrac == DD_GC_FRAC_HI) {
+ (void) fprintf(unique->err,"GC fraction = %.2f\t",
+ DD_GC_FRAC_LO);
+ (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
+ }
+#endif
+ unique->gcFrac = DD_GC_FRAC_LO;
+ }
+
+ assert(i != CUDD_MAXINDEX);
+ oldslots = unique->subtableZ[i].slots;
+ oldshift = unique->subtableZ[i].shift;
+ oldnodelist = unique->subtableZ[i].nodelist;
+
+ /* Compute the new size of the subtable. Normally, we just
+ ** double. However, after reordering, a table may be severely
+ ** overloaded. Therefore, we iterate. */
+ slots = oldslots;
+ shift = oldshift;
+ do {
+ slots <<= 1;
+ shift--;
+ } while (slots * DD_MAX_SUBTABLE_DENSITY < unique->subtableZ[i].keys);
+
+ saveHandler = MMoutOfMemory;
+ MMoutOfMemory = Cudd_OutOfMem;
+ nodelist = ALLOC(DdNodePtr, slots);
+ MMoutOfMemory = saveHandler;
+ if (nodelist == NULL) {
+ int j;
+ (void) fprintf(unique->err,
+ "Unable to resize ZDD subtable %d for lack of memory.\n",
+ i);
+ (void) cuddGarbageCollectZdd(unique,1);
+ for (j = 0; j < unique->sizeZ; j++) {
+ unique->subtableZ[j].maxKeys <<= 1;
+ }
+ return;
+ }
+ unique->subtableZ[i].nodelist = nodelist;
+ unique->subtableZ[i].slots = slots;
+ unique->subtableZ[i].shift = shift;
+ unique->subtableZ[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
+ for (j = 0; (unsigned) j < slots; j++) {
+ nodelist[j] = NULL;
+ }
+ for (j = 0; (unsigned) j < oldslots; j++) {
+ node = oldnodelist[j];
+ while (node != NULL) {
+ next = node->next;
+ pos = ddHash(cuddT(node), cuddE(node), shift);
+ node->next = nodelist[pos];
+ nodelist[pos] = node;
+ node = next;
+ }
+ }
+ FREE(oldnodelist);
+
+#ifdef DD_VERBOSE
+ (void) fprintf(unique->err,
+ "rehashing layer %d: keys %d dead %d new size %d\n",
+ i, unique->subtableZ[i].keys,
+ unique->subtableZ[i].dead, slots);
+#endif
+
+ /* Update global data. */
+ unique->memused += (slots - oldslots) * sizeof(DdNode *);
+ unique->slots += (slots - oldslots);
+ ddFixLimits(unique);
+
+} /* end of ddRehashZdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Increases the number of subtables in a unique table so
+ that it meets or exceeds index.]
+
+ Description [Increases the number of subtables in a unique table so
+ that it meets or exceeds index. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddResizeTableZdd]
+
+******************************************************************************/
+static int
+ddResizeTable(
+ DdManager * unique,
+ int index)
+{
+ DdSubtable *newsubtables;
+ DdNodePtr *newnodelist;
+ DdNodePtr *newvars;
+ DdNode *sentinel = &(unique->sentinel);
+ int oldsize,newsize;
+ int i,j,reorderSave;
+ int numSlots = unique->initSlots;
+ int *newperm, *newinvperm, *newmap;
+ DdNode *one, *zero;
+
+ oldsize = unique->size;
+ /* Easy case: there is still room in the current table. */
+ if (index < unique->maxSize) {
+ for (i = oldsize; i <= index; i++) {
+ unique->subtables[i].slots = numSlots;
+ unique->subtables[i].shift = sizeof(int) * 8 -
+ cuddComputeFloorLog2(numSlots);
+ unique->subtables[i].keys = 0;
+ unique->subtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
+ unique->subtables[i].dead = 0;
+ unique->subtables[i].bindVar = 0;
+ unique->subtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
+ unique->subtables[i].pairIndex = 0;
+ unique->subtables[i].varHandled = 0;
+ unique->subtables[i].varToBeGrouped = CUDD_LAZY_NONE;
+
+ unique->perm[i] = i;
+ unique->invperm[i] = i;
+ newnodelist = unique->subtables[i].nodelist =
+ ALLOC(DdNodePtr, numSlots);
+ if (newnodelist == NULL) {
+ for (j = oldsize; j < i; j++) {
+ FREE(unique->subtables[j].nodelist);
+ }
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (j = 0; j < numSlots; j++) {
+ newnodelist[j] = sentinel;
+ }
+ }
+ if (unique->map != NULL) {
+ for (i = oldsize; i <= index; i++) {
+ unique->map[i] = i;
+ }
+ }
+ } else {
+ /* The current table is too small: we need to allocate a new,
+ ** larger one; move all old subtables, and initialize the new
+ ** subtables up to index included.
+ */
+ newsize = index + DD_DEFAULT_RESIZE;
+#ifdef DD_VERBOSE
+ (void) fprintf(unique->err,
+ "Increasing the table size from %d to %d\n",
+ unique->maxSize, newsize);
+#endif
+ newsubtables = ALLOC(DdSubtable,newsize);
+ if (newsubtables == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ newvars = ALLOC(DdNodePtr,newsize);
+ if (newvars == NULL) {
+ FREE(newsubtables);
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ newperm = ALLOC(int,newsize);
+ if (newperm == NULL) {
+ FREE(newsubtables);
+ FREE(newvars);
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ newinvperm = ALLOC(int,newsize);
+ if (newinvperm == NULL) {
+ FREE(newsubtables);
+ FREE(newvars);
+ FREE(newperm);
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ if (unique->map != NULL) {
+ newmap = ALLOC(int,newsize);
+ if (newmap == NULL) {
+ FREE(newsubtables);
+ FREE(newvars);
+ FREE(newperm);
+ FREE(newinvperm);
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ unique->memused += (newsize - unique->maxSize) * sizeof(int);
+ }
+ unique->memused += (newsize - unique->maxSize) * ((numSlots+1) *
+ sizeof(DdNode *) + 2 * sizeof(int) + sizeof(DdSubtable));
+ if (newsize > unique->maxSizeZ) {
+ FREE(unique->stack);
+ unique->stack = ALLOC(DdNodePtr,newsize + 1);
+ if (unique->stack == NULL) {
+ FREE(newsubtables);
+ FREE(newvars);
+ FREE(newperm);
+ FREE(newinvperm);
+ if (unique->map != NULL) {
+ FREE(newmap);
+ }
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ unique->stack[0] = NULL; /* to suppress harmless UMR */
+ unique->memused +=
+ (newsize - ddMax(unique->maxSize,unique->maxSizeZ))
+ * sizeof(DdNode *);
+ }
+ for (i = 0; i < oldsize; i++) {
+ newsubtables[i].slots = unique->subtables[i].slots;
+ newsubtables[i].shift = unique->subtables[i].shift;
+ newsubtables[i].keys = unique->subtables[i].keys;
+ newsubtables[i].maxKeys = unique->subtables[i].maxKeys;
+ newsubtables[i].dead = unique->subtables[i].dead;
+ newsubtables[i].nodelist = unique->subtables[i].nodelist;
+ newsubtables[i].bindVar = unique->subtables[i].bindVar;
+ newsubtables[i].varType = unique->subtables[i].varType;
+ newsubtables[i].pairIndex = unique->subtables[i].pairIndex;
+ newsubtables[i].varHandled = unique->subtables[i].varHandled;
+ newsubtables[i].varToBeGrouped = unique->subtables[i].varToBeGrouped;
+
+ newvars[i] = unique->vars[i];
+ newperm[i] = unique->perm[i];
+ newinvperm[i] = unique->invperm[i];
+ }
+ for (i = oldsize; i <= index; i++) {
+ newsubtables[i].slots = numSlots;
+ newsubtables[i].shift = sizeof(int) * 8 -
+ cuddComputeFloorLog2(numSlots);
+ newsubtables[i].keys = 0;
+ newsubtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
+ newsubtables[i].dead = 0;
+ newsubtables[i].bindVar = 0;
+ newsubtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
+ newsubtables[i].pairIndex = 0;
+ newsubtables[i].varHandled = 0;
+ newsubtables[i].varToBeGrouped = CUDD_LAZY_NONE;
+
+ newperm[i] = i;
+ newinvperm[i] = i;
+ newnodelist = newsubtables[i].nodelist = ALLOC(DdNodePtr, numSlots);
+ if (newnodelist == NULL) {
+ unique->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (j = 0; j < numSlots; j++) {
+ newnodelist[j] = sentinel;
+ }
+ }
+ if (unique->map != NULL) {
+ for (i = 0; i < oldsize; i++) {
+ newmap[i] = unique->map[i];
+ }
+ for (i = oldsize; i <= index; i++) {
+ newmap[i] = i;
+ }
+ FREE(unique->map);
+ unique->map = newmap;
+ }
+ FREE(unique->subtables);
+ unique->subtables = newsubtables;
+ unique->maxSize = newsize;
+ FREE(unique->vars);
+ unique->vars = newvars;
+ FREE(unique->perm);
+ unique->perm = newperm;
+ FREE(unique->invperm);
+ unique->invperm = newinvperm;
+ }
+
+ /* Now that the table is in a coherent state, create the new
+ ** projection functions. We need to temporarily disable reordering,
+ ** because we cannot reorder without projection functions in place.
+ **/
+ one = unique->one;
+ zero = Cudd_Not(one);
+
+ unique->size = index + 1;
+ unique->slots += (index + 1 - oldsize) * numSlots;
+ ddFixLimits(unique);
+
+ reorderSave = unique->autoDyn;
+ unique->autoDyn = 0;
+ for (i = oldsize; i <= index; i++) {
+ unique->vars[i] = cuddUniqueInter(unique,i,one,zero);
+ if (unique->vars[i] == NULL) {
+ unique->autoDyn = reorderSave;
+ for (j = oldsize; j < i; j++) {
+ Cudd_IterDerefBdd(unique,unique->vars[j]);
+ cuddDeallocNode(unique,unique->vars[j]);
+ unique->vars[j] = NULL;
+ }
+ for (j = oldsize; j <= index; j++) {
+ FREE(unique->subtables[j].nodelist);
+ unique->subtables[j].nodelist = NULL;
+ }
+ unique->size = oldsize;
+ unique->slots -= (index + 1 - oldsize) * numSlots;
+ ddFixLimits(unique);
+ return(0);
+ }
+ cuddRef(unique->vars[i]);
+ }
+ unique->autoDyn = reorderSave;
+
+ return(1);
+
+} /* end of ddResizeTable */
+
+
+/**Function********************************************************************
+
+ Synopsis [Searches the subtables above node for a parent.]
+
+ Description [Searches the subtables above node for a parent. Returns 1
+ as soon as one parent is found. Returns 0 is the search is fruitless.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddFindParent(
+ DdManager * table,
+ DdNode * node)
+{
+ int i,j;
+ int slots;
+ DdNodePtr *nodelist;
+ DdNode *f;
+
+ for (i = cuddI(table,node->index) - 1; i >= 0; i--) {
+ nodelist = table->subtables[i].nodelist;
+ slots = table->subtables[i].slots;
+
+ for (j = 0; j < slots; j++) {
+ f = nodelist[j];
+ while (cuddT(f) > node) {
+ f = f->next;
+ }
+ while (cuddT(f) == node && Cudd_Regular(cuddE(f)) > node) {
+ f = f->next;
+ }
+ if (cuddT(f) == node && Cudd_Regular(cuddE(f)) == node) {
+ return(1);
+ }
+ }
+ }
+
+ return(0);
+
+} /* end of cuddFindParent */
+
+
+/**Function********************************************************************
+
+ Synopsis [Adjusts the values of table limits.]
+
+ Description [Adjusts the values of table fields controlling the.
+ sizes of subtables and computed table. If the computed table is too small
+ according to the new values, it is resized.]
+
+ SideEffects [Modifies manager fields. May resize computed table.]
+
+ SeeAlso []
+
+******************************************************************************/
+DD_INLINE
+static void
+ddFixLimits(
+ DdManager *unique)
+{
+ unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots);
+ unique->cacheSlack = (int) ddMin(unique->maxCacheHard,
+ DD_MAX_CACHE_TO_SLOTS_RATIO * unique->slots) -
+ 2 * (int) unique->cacheSlots;
+ if (unique->cacheSlots < unique->slots/2 && unique->cacheSlack >= 0)
+ cuddCacheResize(unique);
+ return;
+
+} /* end of ddFixLimits */
+
+
+#ifndef DD_UNSORTED_FREE_LIST
+/**Function********************************************************************
+
+ Synopsis [Inserts a DdNode in a red/black search tree.]
+
+ Description [Inserts a DdNode in a red/black search tree. Nodes from
+ the same "page" (defined by DD_PAGE_MASK) are linked in a LIFO list.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddOrderedThread]
+
+******************************************************************************/
+static void
+cuddOrderedInsert(
+ DdNodePtr * root,
+ DdNodePtr node)
+{
+ DdNode *scan;
+ DdNodePtr *scanP;
+ DdNodePtr *stack[DD_STACK_SIZE];
+ int stackN = 0;
+
+ scanP = root;
+ while ((scan = *scanP) != NULL) {
+ stack[stackN++] = scanP;
+ if (DD_INSERT_COMPARE(node, scan) == 0) { /* add to page list */
+ DD_NEXT(node) = DD_NEXT(scan);
+ DD_NEXT(scan) = node;
+ return;
+ }
+ scanP = (node < scan) ? &DD_LEFT(scan) : &DD_RIGHT(scan);
+ }
+ DD_RIGHT(node) = DD_LEFT(node) = DD_NEXT(node) = NULL;
+ DD_COLOR(node) = DD_RED;
+ *scanP = node;
+ stack[stackN] = &node;
+ cuddDoRebalance(stack,stackN);
+
+} /* end of cuddOrderedInsert */
+
+
+/**Function********************************************************************
+
+ Synopsis [Threads all the nodes of a search tree into a linear list.]
+
+ Description [Threads all the nodes of a search tree into a linear
+ list. For each node of the search tree, the "left" child, if non-null, has
+ a lower address than its parent, and the "right" child, if non-null, has a
+ higher address than its parent.
+ The list is sorted in order of increasing addresses. The search
+ tree is destroyed as a result of this operation. The last element of
+ the linear list is made to point to the address passed in list. Each
+ node if the search tree is a linearly-linked list of nodes from the
+ same memory page (as defined in DD_PAGE_MASK). When a node is added to
+ the linear list, all the elements of the linked list are added.]
+
+ SideEffects [The search tree is destroyed as a result of this operation.]
+
+ SeeAlso [cuddOrderedInsert]
+
+******************************************************************************/
+static DdNode *
+cuddOrderedThread(
+ DdNode * root,
+ DdNode * list)
+{
+ DdNode *current, *next, *prev, *end;
+
+ current = root;
+ /* The first word in the node is used to implement a stack that holds
+ ** the nodes from the root of the tree to the current node. Here we
+ ** put the root of the tree at the bottom of the stack.
+ */
+ *((DdNodePtr *) current) = NULL;
+
+ while (current != NULL) {
+ if (DD_RIGHT(current) != NULL) {
+ /* If possible, we follow the "right" link. Eventually we'll
+ ** find the node with the largest address in the current tree.
+ ** In this phase we use the first word of a node to implemen
+ ** a stack of the nodes on the path from the root to "current".
+ ** Also, we disconnect the "right" pointers to indicate that
+ ** we have already followed them.
+ */
+ next = DD_RIGHT(current);
+ DD_RIGHT(current) = NULL;
+ *((DdNodePtr *)next) = current;
+ current = next;
+ } else {
+ /* We can't proceed along the "right" links any further.
+ ** Hence "current" is the largest element in the current tree.
+ ** We make this node the new head of "list". (Repeating this
+ ** operation until the tree is empty yields the desired linear
+ ** threading of all nodes.)
+ */
+ prev = *((DdNodePtr *) current); /* save prev node on stack in prev */
+ /* Traverse the linked list of current until the end. */
+ for (end = current; DD_NEXT(end) != NULL; end = DD_NEXT(end));
+ DD_NEXT(end) = list; /* attach "list" at end and make */
+ list = current; /* "current" the new head of "list" */
+ /* Now, if current has a "left" child, we push it on the stack.
+ ** Otherwise, we just continue with the parent of "current".
+ */
+ if (DD_LEFT(current) != NULL) {
+ next = DD_LEFT(current);
+ *((DdNodePtr *) next) = prev;
+ current = next;
+ } else {
+ current = prev;
+ }
+ }
+ }
+
+ return(list);
+
+} /* end of cuddOrderedThread */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the left rotation for red/black trees.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [cuddRotateRight]
+
+******************************************************************************/
+DD_INLINE
+static void
+cuddRotateLeft(
+ DdNodePtr * nodeP)
+{
+ DdNode *newRoot;
+ DdNode *oldRoot = *nodeP;
+
+ *nodeP = newRoot = DD_RIGHT(oldRoot);
+ DD_RIGHT(oldRoot) = DD_LEFT(newRoot);
+ DD_LEFT(newRoot) = oldRoot;
+
+} /* end of cuddRotateLeft */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the right rotation for red/black trees.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [cuddRotateLeft]
+
+******************************************************************************/
+DD_INLINE
+static void
+cuddRotateRight(
+ DdNodePtr * nodeP)
+{
+ DdNode *newRoot;
+ DdNode *oldRoot = *nodeP;
+
+ *nodeP = newRoot = DD_LEFT(oldRoot);
+ DD_LEFT(oldRoot) = DD_RIGHT(newRoot);
+ DD_RIGHT(newRoot) = oldRoot;
+
+} /* end of cuddRotateRight */
+
+
+/**Function********************************************************************
+
+ Synopsis [Rebalances a red/black tree.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+cuddDoRebalance(
+ DdNodePtr ** stack,
+ int stackN)
+{
+ DdNodePtr *xP, *parentP, *grandpaP;
+ DdNode *x, *y, *parent, *grandpa;
+
+ xP = stack[stackN];
+ x = *xP;
+ /* Work our way back up, re-balancing the tree. */
+ while (--stackN >= 0) {
+ parentP = stack[stackN];
+ parent = *parentP;
+ if (DD_IS_BLACK(parent)) break;
+ /* Since the root is black, here a non-null grandparent exists. */
+ grandpaP = stack[stackN-1];
+ grandpa = *grandpaP;
+ if (parent == DD_LEFT(grandpa)) {
+ y = DD_RIGHT(grandpa);
+ if (y != NULL && DD_IS_RED(y)) {
+ DD_COLOR(parent) = DD_BLACK;
+ DD_COLOR(y) = DD_BLACK;
+ DD_COLOR(grandpa) = DD_RED;
+ x = grandpa;
+ stackN--;
+ } else {
+ if (x == DD_RIGHT(parent)) {
+ cuddRotateLeft(parentP);
+ DD_COLOR(x) = DD_BLACK;
+ } else {
+ DD_COLOR(parent) = DD_BLACK;
+ }
+ DD_COLOR(grandpa) = DD_RED;
+ cuddRotateRight(grandpaP);
+ break;
+ }
+ } else {
+ y = DD_LEFT(grandpa);
+ if (y != NULL && DD_IS_RED(y)) {
+ DD_COLOR(parent) = DD_BLACK;
+ DD_COLOR(y) = DD_BLACK;
+ DD_COLOR(grandpa) = DD_RED;
+ x = grandpa;
+ stackN--;
+ } else {
+ if (x == DD_LEFT(parent)) {
+ cuddRotateRight(parentP);
+ DD_COLOR(x) = DD_BLACK;
+ } else {
+ DD_COLOR(parent) = DD_BLACK;
+ }
+ DD_COLOR(grandpa) = DD_RED;
+ cuddRotateLeft(grandpaP);
+ }
+ }
+ }
+ DD_COLOR(*(stack[0])) = DD_BLACK;
+
+} /* end of cuddDoRebalance */
+#endif
+
+
+/**Function********************************************************************
+
+ Synopsis [Fixes a variable tree after the insertion of new subtables.]
+
+ Description [Fixes a variable tree after the insertion of new subtables.
+ After such an insertion, the low fields of the tree below the insertion
+ point are inconsistent.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+ddPatchTree(
+ DdManager *dd,
+ MtrNode *treenode)
+{
+ MtrNode *auxnode = treenode;
+
+ while (auxnode != NULL) {
+ auxnode->low = dd->perm[auxnode->index];
+ if (auxnode->child != NULL) {
+ ddPatchTree(dd, auxnode->child);
+ }
+ auxnode = auxnode->younger;
+ }
+
+ return;
+
+} /* end of ddPatchTree */
+
+
+#ifdef DD_DEBUG
+/**Function********************************************************************
+
+ Synopsis [Checks whether a collision list is ordered.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddCheckCollisionOrdering(
+ DdManager *unique,
+ int i,
+ int j)
+{
+ int slots;
+ DdNode *node, *next;
+ DdNodePtr *nodelist;
+ DdNode *sentinel = &(unique->sentinel);
+
+ nodelist = unique->subtables[i].nodelist;
+ slots = unique->subtables[i].slots;
+ node = nodelist[j];
+ if (node == sentinel) return(1);
+ next = node->next;
+ while (next != sentinel) {
+ if (cuddT(node) < cuddT(next) ||
+ (cuddT(node) == cuddT(next) && cuddE(node) < cuddE(next))) {
+ (void) fprintf(unique->err,
+ "Unordered list: index %u, position %d\n", i, j);
+ return(0);
+ }
+ node = next;
+ next = node->next;
+ }
+ return(1);
+
+} /* end of cuddCheckCollisionOrdering */
+#endif
+
+
+
+
+/**Function********************************************************************
+
+ Synopsis [Reports problem in garbage collection.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [cuddGarbageCollect cuddGarbageCollectZdd]
+
+******************************************************************************/
+static void
+ddReportRefMess(
+ DdManager *unique /* manager */,
+ int i /* table in which the problem occurred */,
+ char *caller /* procedure that detected the problem */)
+{
+ if (i == CUDD_CONST_INDEX) {
+ (void) fprintf(unique->err,
+ "%s: problem in constants\n", caller);
+ } else if (i != -1) {
+ (void) fprintf(unique->err,
+ "%s: problem in table %d\n", caller, i);
+ }
+ (void) fprintf(unique->err, " dead count != deleted\n");
+ (void) fprintf(unique->err, " This problem is often due to a missing \
+call to Cudd_Ref\n or to an extra call to Cudd_RecursiveDeref.\n \
+See the CUDD Programmer's Guide for additional details.");
+ abort();
+
+} /* end of ddReportRefMess */
diff --git a/src/bdd/cudd/cuddUtil.c b/src/bdd/cudd/cuddUtil.c
new file mode 100644
index 00000000..c366d534
--- /dev/null
+++ b/src/bdd/cudd/cuddUtil.c
@@ -0,0 +1,3633 @@
+/**CFile***********************************************************************
+
+ FileName [cuddUtil.c]
+
+ PackageName [cudd]
+
+ Synopsis [Utility functions.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_PrintMinterm()
+ <li> Cudd_PrintDebug()
+ <li> Cudd_DagSize()
+ <li> Cudd_EstimateCofactor()
+ <li> Cudd_EstimateCofactorSimple()
+ <li> Cudd_SharingSize()
+ <li> Cudd_CountMinterm()
+ <li> Cudd_EpdCountMinterm()
+ <li> Cudd_CountPath()
+ <li> Cudd_CountPathsToNonZero()
+ <li> Cudd_Support()
+ <li> Cudd_SupportIndex()
+ <li> Cudd_SupportSize()
+ <li> Cudd_VectorSupport()
+ <li> Cudd_VectorSupportIndex()
+ <li> Cudd_VectorSupportSize()
+ <li> Cudd_ClassifySupport()
+ <li> Cudd_CountLeaves()
+ <li> Cudd_bddPickOneCube()
+ <li> Cudd_bddPickOneMinterm()
+ <li> Cudd_bddPickArbitraryMinterms()
+ <li> Cudd_SubsetWithMaskVars()
+ <li> Cudd_FirstCube()
+ <li> Cudd_NextCube()
+ <li> Cudd_bddComputeCube()
+ <li> Cudd_addComputeCube()
+ <li> Cudd_FirstNode()
+ <li> Cudd_NextNode()
+ <li> Cudd_GenFree()
+ <li> Cudd_IsGenEmpty()
+ <li> Cudd_IndicesToCube()
+ <li> Cudd_PrintVersion()
+ <li> Cudd_AverageDistance()
+ <li> Cudd_Random()
+ <li> Cudd_Srandom()
+ <li> Cudd_Density()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddP()
+ <li> cuddStCountfree()
+ <li> cuddCollectNodes()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> dp2()
+ <li> ddPrintMintermAux()
+ <li> ddDagInt()
+ <li> ddCountMintermAux()
+ <li> ddEpdCountMintermAux()
+ <li> ddCountPathAux()
+ <li> ddSupportStep()
+ <li> ddClearFlag()
+ <li> ddLeavesInt()
+ <li> ddPickArbitraryMinterms()
+ <li> ddPickRepresentativeCube()
+ <li> ddEpdFree()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/* Random generator constants. */
+#define MODULUS1 2147483563
+#define LEQA1 40014
+#define LEQQ1 53668
+#define LEQR1 12211
+#define MODULUS2 2147483399
+#define LEQA2 40692
+#define LEQQ2 52774
+#define LEQR2 3791
+#define STAB_SIZE 64
+#define STAB_DIV (1 + (MODULUS1 - 1) / STAB_SIZE)
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddUtil.c,v 1.1.1.1 2003/02/24 22:23:53 wjiang Exp $";
+#endif
+
+static DdNode *background, *zero;
+
+static long cuddRand = 0;
+static long cuddRand2;
+static long shuffleSelect;
+static long shuffleTable[STAB_SIZE];
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+#define bang(f) ((Cudd_IsComplement(f)) ? '!' : ' ')
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int dp2 ARGS((DdManager *dd, DdNode *f, st_table *t));
+static void ddPrintMintermAux ARGS((DdManager *dd, DdNode *node, int *list));
+static int ddDagInt ARGS((DdNode *n));
+static int cuddEstimateCofactor ARGS((DdManager *dd, st_table *table, DdNode * node, int i, int phase, DdNode ** ptr));
+static DdNode * cuddUniqueLookup ARGS((DdManager * unique, int index, DdNode * T, DdNode * E));
+static int cuddEstimateCofactorSimple ARGS((DdNode * node, int i));
+static double ddCountMintermAux ARGS((DdNode *node, double max, DdHashTable *table));
+static int ddEpdCountMintermAux ARGS((DdNode *node, EpDouble *max, EpDouble *epd, st_table *table));
+static double ddCountPathAux ARGS((DdNode *node, st_table *table));
+static double ddCountPathsToNonZero ARGS((DdNode * N, st_table * table));
+static void ddSupportStep ARGS((DdNode *f, int *support));
+static void ddClearFlag ARGS((DdNode *f));
+static int ddLeavesInt ARGS((DdNode *n));
+static int ddPickArbitraryMinterms ARGS((DdManager *dd, DdNode *node, int nvars, int nminterms, char **string));
+static int ddPickRepresentativeCube ARGS((DdManager *dd, DdNode *node, int nvars, double *weight, char *string));
+static enum st_retval ddEpdFree ARGS((char * key, char * value, char * arg));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints a disjoint sum of products.]
+
+ Description [Prints a disjoint sum of product cover for the function
+ rooted at node. Each product corresponds to a path from node to a
+ leaf node different from the logical zero, and different from the
+ background value. Uses the package default output file. Returns 1
+ if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_PrintDebug Cudd_bddPrintCover]
+
+******************************************************************************/
+int
+Cudd_PrintMinterm(
+ DdManager * manager,
+ DdNode * node)
+{
+ int i, *list;
+
+ background = manager->background;
+ zero = Cudd_Not(manager->one);
+ list = ALLOC(int,manager->size);
+ if (list == NULL) {
+ manager->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (i = 0; i < manager->size; i++) list[i] = 2;
+ ddPrintMintermAux(manager,node,list);
+ FREE(list);
+ return(1);
+
+} /* end of Cudd_PrintMinterm */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints a sum of prime implicants of a BDD.]
+
+ Description [Prints a sum of product cover for an incompletely
+ specified function given by a lower bound and an upper bound. Each
+ product is a prime implicant obtained by expanding the product
+ corresponding to a path from node to the constant one. Uses the
+ package default output file. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_PrintMinterm]
+
+******************************************************************************/
+int
+Cudd_bddPrintCover(
+ DdManager *dd,
+ DdNode *l,
+ DdNode *u)
+{
+ int *array;
+ int q, result;
+ DdNode *lb;
+#ifdef DD_DEBUG
+ DdNode *cover;
+#endif
+
+ array = ALLOC(int, Cudd_ReadSize(dd));
+ if (array == NULL) return(0);
+ lb = l;
+ cuddRef(lb);
+#ifdef DD_DEBUG
+ cover = Cudd_ReadLogicZero(dd);
+ cuddRef(cover);
+#endif
+ while (lb != Cudd_ReadLogicZero(dd)) {
+ DdNode *implicant, *prime, *tmp;
+ int length;
+ implicant = Cudd_LargestCube(dd,lb,&length);
+ if (implicant == NULL) {
+ Cudd_RecursiveDeref(dd,lb);
+ FREE(array);
+ return(0);
+ }
+ cuddRef(implicant);
+ prime = Cudd_bddMakePrime(dd,implicant,u);
+ if (prime == NULL) {
+ Cudd_RecursiveDeref(dd,lb);
+ Cudd_RecursiveDeref(dd,implicant);
+ FREE(array);
+ return(0);
+ }
+ cuddRef(prime);
+ Cudd_RecursiveDeref(dd,implicant);
+ tmp = Cudd_bddAnd(dd,lb,Cudd_Not(prime));
+ if (tmp == NULL) {
+ Cudd_RecursiveDeref(dd,lb);
+ Cudd_RecursiveDeref(dd,prime);
+ FREE(array);
+ return(0);
+ }
+ cuddRef(tmp);
+ Cudd_RecursiveDeref(dd,lb);
+ lb = tmp;
+ result = Cudd_BddToCubeArray(dd,prime,array);
+ if (result == 0) {
+ Cudd_RecursiveDeref(dd,lb);
+ Cudd_RecursiveDeref(dd,prime);
+ FREE(array);
+ return(0);
+ }
+ for (q = 0; q < dd->size; q++) {
+ switch (array[q]) {
+ case 0:
+ (void) fprintf(dd->out, "0");
+ break;
+ case 1:
+ (void) fprintf(dd->out, "1");
+ break;
+ case 2:
+ (void) fprintf(dd->out, "-");
+ break;
+ default:
+ (void) fprintf(dd->out, "?");
+ }
+ }
+ (void) fprintf(dd->out, " 1\n");
+#ifdef DD_DEBUG
+ tmp = Cudd_bddOr(dd,prime,cover);
+ if (tmp == NULL) {
+ Cudd_RecursiveDeref(dd,cover);
+ Cudd_RecursiveDeref(dd,lb);
+ Cudd_RecursiveDeref(dd,prime);
+ FREE(array);
+ return(0);
+ }
+ cuddRef(tmp);
+ Cudd_RecursiveDeref(dd,cover);
+ cover = tmp;
+#endif
+ Cudd_RecursiveDeref(dd,prime);
+ }
+ (void) fprintf(dd->out, "\n");
+ Cudd_RecursiveDeref(dd,lb);
+ FREE(array);
+#ifdef DD_DEBUG
+ if (!Cudd_bddLeq(dd,cover,u) || !Cudd_bddLeq(dd,l,cover)) {
+ Cudd_RecursiveDeref(dd,cover);
+ return(0);
+ }
+ Cudd_RecursiveDeref(dd,cover);
+#endif
+ return(1);
+
+} /* end of Cudd_bddPrintCover */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints to the standard output a DD and its statistics.]
+
+ Description [Prints to the standard output a DD and its statistics.
+ The statistics include the number of nodes, the number of leaves, and
+ the number of minterms. (The number of minterms is the number of
+ assignments to the variables that cause the function to be different
+ from the logical zero (for BDDs) and from the background value (for
+ ADDs.) The statistics are printed if pr &gt; 0. Specifically:
+ <ul>
+ <li> pr = 0 : prints nothing
+ <li> pr = 1 : prints counts of nodes and minterms
+ <li> pr = 2 : prints counts + disjoint sum of product
+ <li> pr = 3 : prints counts + list of nodes
+ <li> pr &gt; 3 : prints counts + disjoint sum of product + list of nodes
+ </ul>
+ For the purpose of counting the number of minterms, the function is
+ supposed to depend on n variables. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DagSize Cudd_CountLeaves Cudd_CountMinterm
+ Cudd_PrintMinterm]
+
+******************************************************************************/
+int
+Cudd_PrintDebug(
+ DdManager * dd,
+ DdNode * f,
+ int n,
+ int pr)
+{
+ DdNode *azero, *bzero;
+ int nodes;
+ int leaves;
+ double minterms;
+ int retval = 1;
+
+ if (f == NULL) {
+ (void) fprintf(dd->out,": is the NULL DD\n");
+ (void) fflush(dd->out);
+ return(0);
+ }
+ azero = DD_ZERO(dd);
+ bzero = Cudd_Not(DD_ONE(dd));
+ if ((f == azero || f == bzero) && pr > 0){
+ (void) fprintf(dd->out,": is the zero DD\n");
+ (void) fflush(dd->out);
+ return(1);
+ }
+ if (pr > 0) {
+ nodes = Cudd_DagSize(f);
+ if (nodes == CUDD_OUT_OF_MEM) retval = 0;
+ leaves = Cudd_CountLeaves(f);
+ if (leaves == CUDD_OUT_OF_MEM) retval = 0;
+ minterms = Cudd_CountMinterm(dd, f, n);
+ if (minterms == (double)CUDD_OUT_OF_MEM) retval = 0;
+ (void) fprintf(dd->out,": %d nodes %d leaves %g minterms\n",
+ nodes, leaves, minterms);
+ if (pr > 2) {
+ if (!cuddP(dd, f)) retval = 0;
+ }
+ if (pr == 2 || pr > 3) {
+ if (!Cudd_PrintMinterm(dd,f)) retval = 0;
+ (void) fprintf(dd->out,"\n");
+ }
+ (void) fflush(dd->out);
+ }
+ return(retval);
+
+} /* end of Cudd_PrintDebug */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the number of nodes in a DD.]
+
+ Description [Counts the number of nodes in a DD. Returns the number
+ of nodes in the graph rooted at node.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SharingSize Cudd_PrintDebug]
+
+******************************************************************************/
+int
+Cudd_DagSize(
+ DdNode * node)
+{
+ int i;
+
+ i = ddDagInt(Cudd_Regular(node));
+ ddClearFlag(Cudd_Regular(node));
+
+ return(i);
+
+} /* end of Cudd_DagSize */
+
+
+/**Function********************************************************************
+
+ Synopsis [Estimates the number of nodes in a cofactor of a DD.]
+
+ Description [Estimates the number of nodes in a cofactor of a DD.
+ Returns an estimate of the number of nodes in a cofactor of
+ the graph rooted at node with respect to the variable whose index is i.
+ In case of failure, returns CUDD_OUT_OF_MEM.
+ This function uses a refinement of the algorithm of Cabodi et al.
+ (ICCAD96). The refinement allows the procedure to account for part
+ of the recombination that may occur in the part of the cofactor above
+ the cofactoring variable. This procedure does no create any new node.
+ It does keep a small table of results; therefore itmay run out of memory.
+ If this is a concern, one should use Cudd_EstimateCofactorSimple, which
+ is faster, does not allocate any memory, but is less accurate.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DagSize Cudd_EstimateCofactorSimple]
+
+******************************************************************************/
+int
+Cudd_EstimateCofactor(
+ DdManager *dd /* manager */,
+ DdNode * f /* function */,
+ int i /* index of variable */,
+ int phase /* 1: positive; 0: negative */
+ )
+{
+ int val;
+ DdNode *ptr;
+ st_table *table;
+
+ table = st_init_table(st_ptrcmp,st_ptrhash);
+ if (table == NULL) return(CUDD_OUT_OF_MEM);
+ val = cuddEstimateCofactor(dd,table,Cudd_Regular(f),i,phase,&ptr);
+ ddClearFlag(Cudd_Regular(f));
+ st_free_table(table);
+
+ return(val);
+
+} /* end of Cudd_EstimateCofactor */
+
+
+/**Function********************************************************************
+
+ Synopsis [Estimates the number of nodes in a cofactor of a DD.]
+
+ Description [Estimates the number of nodes in a cofactor of a DD.
+ Returns an estimate of the number of nodes in the positive cofactor of
+ the graph rooted at node with respect to the variable whose index is i.
+ This procedure implements with minor changes the algorithm of Cabodi et al.
+ (ICCAD96). It does not allocate any memory, it does not change the
+ state of the manager, and it is fast. However, it has been observed to
+ overestimate the size of the cofactor by as much as a factor of 2.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DagSize]
+
+******************************************************************************/
+int
+Cudd_EstimateCofactorSimple(
+ DdNode * node,
+ int i)
+{
+ int val;
+
+ val = cuddEstimateCofactorSimple(Cudd_Regular(node),i);
+ ddClearFlag(Cudd_Regular(node));
+
+ return(val);
+
+} /* end of Cudd_EstimateCofactorSimple */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the number of nodes in an array of DDs.]
+
+ Description [Counts the number of nodes in an array of DDs. Shared
+ nodes are counted only once. Returns the total number of nodes.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DagSize]
+
+******************************************************************************/
+int
+Cudd_SharingSize(
+ DdNode ** nodeArray,
+ int n)
+{
+ int i,j;
+
+ i = 0;
+ for (j = 0; j < n; j++) {
+ i += ddDagInt(Cudd_Regular(nodeArray[j]));
+ }
+ for (j = 0; j < n; j++) {
+ ddClearFlag(Cudd_Regular(nodeArray[j]));
+ }
+ return(i);
+
+} /* end of Cudd_SharingSize */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the number of minterms of a DD.]
+
+ Description [Counts the number of minterms of a DD. The function is
+ assumed to depend on nvars variables. The minterm count is
+ represented as a double, to allow for a larger number of variables.
+ Returns the number of minterms of the function rooted at node if
+ successful; (double) CUDD_OUT_OF_MEM otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_PrintDebug Cudd_CountPath]
+
+******************************************************************************/
+double
+Cudd_CountMinterm(
+ DdManager * manager,
+ DdNode * node,
+ int nvars)
+{
+ double max;
+ DdHashTable *table;
+ double res;
+ CUDD_VALUE_TYPE epsilon;
+
+ background = manager->background;
+ zero = Cudd_Not(manager->one);
+
+ max = pow(2.0,(double)nvars);
+ table = cuddHashTableInit(manager,1,2);
+ if (table == NULL) {
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ epsilon = Cudd_ReadEpsilon(manager);
+ Cudd_SetEpsilon(manager,(CUDD_VALUE_TYPE)0.0);
+ res = ddCountMintermAux(node,max,table);
+ cuddHashTableQuit(table);
+ Cudd_SetEpsilon(manager,epsilon);
+
+ return(res);
+
+} /* end of Cudd_CountMinterm */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the number of paths of a DD.]
+
+ Description [Counts the number of paths of a DD. Paths to all
+ terminal nodes are counted. The path count is represented as a
+ double, to allow for a larger number of variables. Returns the
+ number of paths of the function rooted at node if successful;
+ (double) CUDD_OUT_OF_MEM otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_CountMinterm]
+
+******************************************************************************/
+double
+Cudd_CountPath(
+ DdNode * node)
+{
+
+ st_table *table;
+ double i;
+
+ table = st_init_table(st_ptrcmp,st_ptrhash);
+ if (table == NULL) {
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ i = ddCountPathAux(Cudd_Regular(node),table);
+ st_foreach(table, cuddStCountfree, NULL);
+ st_free_table(table);
+ return(i);
+
+} /* end of Cudd_CountPath */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the number of minterms of a DD with extended precision.]
+
+ Description [Counts the number of minterms of a DD with extended precision.
+ The function is assumed to depend on nvars variables. The minterm count is
+ represented as an EpDouble, to allow any number of variables.
+ Returns 0 if successful; CUDD_OUT_OF_MEM otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_PrintDebug Cudd_CountPath]
+
+******************************************************************************/
+int
+Cudd_EpdCountMinterm(
+ DdManager * manager,
+ DdNode * node,
+ int nvars,
+ EpDouble * epd)
+{
+ EpDouble max, tmp;
+ st_table *table;
+ int status;
+
+ background = manager->background;
+ zero = Cudd_Not(manager->one);
+
+ EpdPow2(nvars, &max);
+ table = st_init_table(EpdCmp, st_ptrhash);
+ if (table == NULL) {
+ EpdMakeZero(epd, 0);
+ return(CUDD_OUT_OF_MEM);
+ }
+ status = ddEpdCountMintermAux(Cudd_Regular(node),&max,epd,table);
+ st_foreach(table, ddEpdFree, NULL);
+ st_free_table(table);
+ if (status == CUDD_OUT_OF_MEM) {
+ EpdMakeZero(epd, 0);
+ return(CUDD_OUT_OF_MEM);
+ }
+ if (Cudd_IsComplement(node)) {
+ EpdSubtract3(&max, epd, &tmp);
+ EpdCopy(&tmp, epd);
+ }
+ return(0);
+
+} /* end of Cudd_EpdCountMinterm */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the number of paths to a non-zero terminal of a DD.]
+
+ Description [Counts the number of paths to a non-zero terminal of a
+ DD. The path count is
+ represented as a double, to allow for a larger number of variables.
+ Returns the number of paths of the function rooted at node.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_CountMinterm Cudd_CountPath]
+
+******************************************************************************/
+double
+Cudd_CountPathsToNonZero(
+ DdNode * node)
+{
+
+ st_table *table;
+ double i;
+
+ table = st_init_table(st_ptrcmp,st_ptrhash);
+ if (table == NULL) {
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ i = ddCountPathsToNonZero(node,table);
+ st_foreach(table, cuddStCountfree, NULL);
+ st_free_table(table);
+ return(i);
+
+} /* end of Cudd_CountPathsToNonZero */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the variables on which a DD depends.]
+
+ Description [Finds the variables on which a DD depends.
+ Returns a BDD consisting of the product of the variables if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_VectorSupport Cudd_ClassifySupport]
+
+******************************************************************************/
+DdNode *
+Cudd_Support(
+ DdManager * dd /* manager */,
+ DdNode * f /* DD whose support is sought */)
+{
+ int *support;
+ DdNode *res, *tmp, *var;
+ int i,j;
+ int size;
+
+ /* Allocate and initialize support array for ddSupportStep. */
+ size = ddMax(dd->size, dd->sizeZ);
+ support = ALLOC(int,size);
+ if (support == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < size; i++) {
+ support[i] = 0;
+ }
+
+ /* Compute support and clean up markers. */
+ ddSupportStep(Cudd_Regular(f),support);
+ ddClearFlag(Cudd_Regular(f));
+
+ /* Transform support from array to cube. */
+ do {
+ dd->reordered = 0;
+ res = DD_ONE(dd);
+ cuddRef(res);
+ for (j = size - 1; j >= 0; j--) { /* for each level bottom-up */
+ i = (j >= dd->size) ? j : dd->invperm[j];
+ if (support[i] == 1) {
+ var = cuddUniqueInter(dd,i,dd->one,Cudd_Not(dd->one));
+ cuddRef(var);
+ tmp = cuddBddAndRecur(dd,res,var);
+ if (tmp == NULL) {
+ Cudd_RecursiveDeref(dd,res);
+ Cudd_RecursiveDeref(dd,var);
+ res = NULL;
+ break;
+ }
+ cuddRef(tmp);
+ Cudd_RecursiveDeref(dd,res);
+ Cudd_RecursiveDeref(dd,var);
+ res = tmp;
+ }
+ }
+ } while (dd->reordered == 1);
+
+ FREE(support);
+ if (res != NULL) cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_Support */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the variables on which a DD depends.]
+
+ Description [Finds the variables on which a DD depends.
+ Returns an index array of the variables if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Support Cudd_VectorSupport Cudd_ClassifySupport]
+
+******************************************************************************/
+int *
+Cudd_SupportIndex(
+ DdManager * dd /* manager */,
+ DdNode * f /* DD whose support is sought */)
+{
+ int *support;
+ int i;
+ int size;
+
+ /* Allocate and initialize support array for ddSupportStep. */
+ size = ddMax(dd->size, dd->sizeZ);
+ support = ALLOC(int,size);
+ if (support == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < size; i++) {
+ support[i] = 0;
+ }
+
+ /* Compute support and clean up markers. */
+ ddSupportStep(Cudd_Regular(f),support);
+ ddClearFlag(Cudd_Regular(f));
+
+ return(support);
+
+} /* end of Cudd_SupportIndex */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the variables on which a DD depends.]
+
+ Description [Counts the variables on which a DD depends.
+ Returns the number of the variables if successful; CUDD_OUT_OF_MEM
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Support]
+
+******************************************************************************/
+int
+Cudd_SupportSize(
+ DdManager * dd /* manager */,
+ DdNode * f /* DD whose support size is sought */)
+{
+ int *support;
+ int i;
+ int size;
+ int count;
+
+ /* Allocate and initialize support array for ddSupportStep. */
+ size = ddMax(dd->size, dd->sizeZ);
+ support = ALLOC(int,size);
+ if (support == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(CUDD_OUT_OF_MEM);
+ }
+ for (i = 0; i < size; i++) {
+ support[i] = 0;
+ }
+
+ /* Compute support and clean up markers. */
+ ddSupportStep(Cudd_Regular(f),support);
+ ddClearFlag(Cudd_Regular(f));
+
+ /* Count support variables. */
+ count = 0;
+ for (i = 0; i < size; i++) {
+ if (support[i] == 1) count++;
+ }
+
+ FREE(support);
+ return(count);
+
+} /* end of Cudd_SupportSize */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the variables on which a set of DDs depends.]
+
+ Description [Finds the variables on which a set of DDs depends.
+ The set must contain either BDDs and ADDs, or ZDDs.
+ Returns a BDD consisting of the product of the variables if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Support Cudd_ClassifySupport]
+
+******************************************************************************/
+DdNode *
+Cudd_VectorSupport(
+ DdManager * dd /* manager */,
+ DdNode ** F /* array of DDs whose support is sought */,
+ int n /* size of the array */)
+{
+ int *support;
+ DdNode *res, *tmp, *var;
+ int i,j;
+ int size;
+
+ /* Allocate and initialize support array for ddSupportStep. */
+ size = ddMax(dd->size, dd->sizeZ);
+ support = ALLOC(int,size);
+ if (support == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < size; i++) {
+ support[i] = 0;
+ }
+
+ /* Compute support and clean up markers. */
+ for (i = 0; i < n; i++) {
+ ddSupportStep(Cudd_Regular(F[i]),support);
+ }
+ for (i = 0; i < n; i++) {
+ ddClearFlag(Cudd_Regular(F[i]));
+ }
+
+ /* Transform support from array to cube. */
+ res = DD_ONE(dd);
+ cuddRef(res);
+ for (j = size - 1; j >= 0; j--) { /* for each level bottom-up */
+ i = (j >= dd->size) ? j : dd->invperm[j];
+ if (support[i] == 1) {
+ var = cuddUniqueInter(dd,i,dd->one,Cudd_Not(dd->one));
+ cuddRef(var);
+ tmp = Cudd_bddAnd(dd,res,var);
+ if (tmp == NULL) {
+ Cudd_RecursiveDeref(dd,res);
+ Cudd_RecursiveDeref(dd,var);
+ FREE(support);
+ return(NULL);
+ }
+ cuddRef(tmp);
+ Cudd_RecursiveDeref(dd,res);
+ Cudd_RecursiveDeref(dd,var);
+ res = tmp;
+ }
+ }
+
+ FREE(support);
+ cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_VectorSupport */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the variables on which a set of DDs depends.]
+
+ Description [Finds the variables on which a set of DDs depends.
+ The set must contain either BDDs and ADDs, or ZDDs.
+ Returns an index array of the variables if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SupportIndex Cudd_VectorSupport Cudd_ClassifySupport]
+
+******************************************************************************/
+int *
+Cudd_VectorSupportIndex(
+ DdManager * dd /* manager */,
+ DdNode ** F /* array of DDs whose support is sought */,
+ int n /* size of the array */)
+{
+ int *support;
+ int i;
+ int size;
+
+ /* Allocate and initialize support array for ddSupportStep. */
+ size = ddMax(dd->size, dd->sizeZ);
+ support = ALLOC(int,size);
+ if (support == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < size; i++) {
+ support[i] = 0;
+ }
+
+ /* Compute support and clean up markers. */
+ for (i = 0; i < n; i++) {
+ ddSupportStep(Cudd_Regular(F[i]),support);
+ }
+ for (i = 0; i < n; i++) {
+ ddClearFlag(Cudd_Regular(F[i]));
+ }
+
+ return(support);
+
+} /* end of Cudd_VectorSupportIndex */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the variables on which a set of DDs depends.]
+
+ Description [Counts the variables on which a set of DDs depends.
+ The set must contain either BDDs and ADDs, or ZDDs.
+ Returns the number of the variables if successful; CUDD_OUT_OF_MEM
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_VectorSupport Cudd_SupportSize]
+
+******************************************************************************/
+int
+Cudd_VectorSupportSize(
+ DdManager * dd /* manager */,
+ DdNode ** F /* array of DDs whose support is sought */,
+ int n /* size of the array */)
+{
+ int *support;
+ int i;
+ int size;
+ int count;
+
+ /* Allocate and initialize support array for ddSupportStep. */
+ size = ddMax(dd->size, dd->sizeZ);
+ support = ALLOC(int,size);
+ if (support == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(CUDD_OUT_OF_MEM);
+ }
+ for (i = 0; i < size; i++) {
+ support[i] = 0;
+ }
+
+ /* Compute support and clean up markers. */
+ for (i = 0; i < n; i++) {
+ ddSupportStep(Cudd_Regular(F[i]),support);
+ }
+ for (i = 0; i < n; i++) {
+ ddClearFlag(Cudd_Regular(F[i]));
+ }
+
+ /* Count vriables in support. */
+ count = 0;
+ for (i = 0; i < size; i++) {
+ if (support[i] == 1) count++;
+ }
+
+ FREE(support);
+ return(count);
+
+} /* end of Cudd_VectorSupportSize */
+
+
+/**Function********************************************************************
+
+ Synopsis [Classifies the variables in the support of two DDs.]
+
+ Description [Classifies the variables in the support of two DDs
+ <code>f</code> and <code>g</code>, depending on whther they appear
+ in both DDs, only in <code>f</code>, or only in <code>g</code>.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [The cubes of the three classes of variables are
+ returned as side effects.]
+
+ SeeAlso [Cudd_Support Cudd_VectorSupport]
+
+******************************************************************************/
+int
+Cudd_ClassifySupport(
+ DdManager * dd /* manager */,
+ DdNode * f /* first DD */,
+ DdNode * g /* second DD */,
+ DdNode ** common /* cube of shared variables */,
+ DdNode ** onlyF /* cube of variables only in f */,
+ DdNode ** onlyG /* cube of variables only in g */)
+{
+ int *supportF, *supportG;
+ DdNode *tmp, *var;
+ int i,j;
+ int size;
+
+ /* Allocate and initialize support arrays for ddSupportStep. */
+ size = ddMax(dd->size, dd->sizeZ);
+ supportF = ALLOC(int,size);
+ if (supportF == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ supportG = ALLOC(int,size);
+ if (supportG == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ FREE(supportF);
+ return(0);
+ }
+ for (i = 0; i < size; i++) {
+ supportF[i] = 0;
+ supportG[i] = 0;
+ }
+
+ /* Compute supports and clean up markers. */
+ ddSupportStep(Cudd_Regular(f),supportF);
+ ddClearFlag(Cudd_Regular(f));
+ ddSupportStep(Cudd_Regular(g),supportG);
+ ddClearFlag(Cudd_Regular(g));
+
+ /* Classify variables and create cubes. */
+ *common = *onlyF = *onlyG = DD_ONE(dd);
+ cuddRef(*common); cuddRef(*onlyF); cuddRef(*onlyG);
+ for (j = size - 1; j >= 0; j--) { /* for each level bottom-up */
+ i = (j >= dd->size) ? j : dd->invperm[j];
+ if (supportF[i] == 0 && supportG[i] == 0) continue;
+ var = cuddUniqueInter(dd,i,dd->one,Cudd_Not(dd->one));
+ cuddRef(var);
+ if (supportG[i] == 0) {
+ tmp = Cudd_bddAnd(dd,*onlyF,var);
+ if (tmp == NULL) {
+ Cudd_RecursiveDeref(dd,*common);
+ Cudd_RecursiveDeref(dd,*onlyF);
+ Cudd_RecursiveDeref(dd,*onlyG);
+ Cudd_RecursiveDeref(dd,var);
+ FREE(supportF); FREE(supportG);
+ return(0);
+ }
+ cuddRef(tmp);
+ Cudd_RecursiveDeref(dd,*onlyF);
+ *onlyF = tmp;
+ } else if (supportF[i] == 0) {
+ tmp = Cudd_bddAnd(dd,*onlyG,var);
+ if (tmp == NULL) {
+ Cudd_RecursiveDeref(dd,*common);
+ Cudd_RecursiveDeref(dd,*onlyF);
+ Cudd_RecursiveDeref(dd,*onlyG);
+ Cudd_RecursiveDeref(dd,var);
+ FREE(supportF); FREE(supportG);
+ return(0);
+ }
+ cuddRef(tmp);
+ Cudd_RecursiveDeref(dd,*onlyG);
+ *onlyG = tmp;
+ } else {
+ tmp = Cudd_bddAnd(dd,*common,var);
+ if (tmp == NULL) {
+ Cudd_RecursiveDeref(dd,*common);
+ Cudd_RecursiveDeref(dd,*onlyF);
+ Cudd_RecursiveDeref(dd,*onlyG);
+ Cudd_RecursiveDeref(dd,var);
+ FREE(supportF); FREE(supportG);
+ return(0);
+ }
+ cuddRef(tmp);
+ Cudd_RecursiveDeref(dd,*common);
+ *common = tmp;
+ }
+ Cudd_RecursiveDeref(dd,var);
+ }
+
+ FREE(supportF); FREE(supportG);
+ cuddDeref(*common); cuddDeref(*onlyF); cuddDeref(*onlyG);
+ return(1);
+
+} /* end of Cudd_ClassifySupport */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the number of leaves in a DD.]
+
+ Description [Counts the number of leaves in a DD. Returns the number
+ of leaves in the DD rooted at node if successful; CUDD_OUT_OF_MEM
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_PrintDebug]
+
+******************************************************************************/
+int
+Cudd_CountLeaves(
+ DdNode * node)
+{
+ int i;
+
+ i = ddLeavesInt(Cudd_Regular(node));
+ ddClearFlag(Cudd_Regular(node));
+ return(i);
+
+} /* end of Cudd_CountLeaves */
+
+
+/**Function********************************************************************
+
+ Synopsis [Picks one on-set cube randomly from the given DD.]
+
+ Description [Picks one on-set cube randomly from the given DD. The
+ cube is written into an array of characters. The array must have at
+ least as many entries as there are variables. Returns 1 if
+ successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddPickOneMinterm]
+
+******************************************************************************/
+int
+Cudd_bddPickOneCube(
+ DdManager * ddm,
+ DdNode * node,
+ char * string)
+{
+ DdNode *N, *T, *E;
+ DdNode *one, *bzero;
+ char dir;
+ int i;
+
+ if (string == NULL || node == NULL) return(0);
+
+ /* The constant 0 function has no on-set cubes. */
+ one = DD_ONE(ddm);
+ bzero = Cudd_Not(one);
+ if (node == bzero) return(0);
+
+ for (i = 0; i < ddm->size; i++) string[i] = 2;
+
+ for (;;) {
+
+ if (node == one) break;
+
+ N = Cudd_Regular(node);
+
+ T = cuddT(N); E = cuddE(N);
+ if (Cudd_IsComplement(node)) {
+ T = Cudd_Not(T); E = Cudd_Not(E);
+ }
+ if (T == bzero) {
+ string[N->index] = 0;
+ node = E;
+ } else if (E == bzero) {
+ string[N->index] = 1;
+ node = T;
+ } else {
+ dir = (char) ((Cudd_Random() & 0x2000) >> 13);
+ string[N->index] = dir;
+ node = dir ? T : E;
+ }
+ }
+ return(1);
+
+} /* end of Cudd_bddPickOneCube */
+
+
+/**Function********************************************************************
+
+ Synopsis [Picks one on-set minterm randomly from the given DD.]
+
+ Description [Picks one on-set minterm randomly from the given
+ DD. The minterm is in terms of <code>vars</code>. The array
+ <code>vars</code> should contain at least all variables in the
+ support of <code>f</code>; if this condition is not met the minterm
+ built by this procedure may not be contained in
+ <code>f</code>. Builds a BDD for the minterm and returns a pointer
+ to it if successful; NULL otherwise. There are three reasons why the
+ procedure may fail:
+ <ul>
+ <li> It may run out of memory;
+ <li> the function <code>f</code> may be the constant 0;
+ <li> the minterm may not be contained in <code>f</code>.
+ </ul>]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddPickOneCube]
+
+******************************************************************************/
+DdNode *
+Cudd_bddPickOneMinterm(
+ DdManager * dd /* manager */,
+ DdNode * f /* function from which to pick one minterm */,
+ DdNode ** vars /* array of variables */,
+ int n /* size of <code>vars</code> */)
+{
+ char *string;
+ int i, size;
+ int *indices;
+ int result;
+ DdNode *old, *neW;
+
+ size = dd->size;
+ string = ALLOC(char, size);
+ if (string == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ indices = ALLOC(int,n);
+ if (indices == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ FREE(string);
+ return(NULL);
+ }
+
+ for (i = 0; i < n; i++) {
+ indices[i] = vars[i]->index;
+ }
+
+ result = Cudd_bddPickOneCube(dd,f,string);
+ if (result == 0) {
+ FREE(string);
+ FREE(indices);
+ return(NULL);
+ }
+
+ /* Randomize choice for don't cares. */
+ for (i = 0; i < n; i++) {
+ if (string[indices[i]] == 2)
+ string[indices[i]] = (char) ((Cudd_Random() & 0x20) >> 5);
+ }
+
+ /* Build result BDD. */
+ old = Cudd_ReadOne(dd);
+ cuddRef(old);
+
+ for (i = n-1; i >= 0; i--) {
+ neW = Cudd_bddAnd(dd,old,Cudd_NotCond(vars[i],string[indices[i]]==0));
+ if (neW == NULL) {
+ FREE(string);
+ FREE(indices);
+ Cudd_RecursiveDeref(dd,old);
+ return(NULL);
+ }
+ cuddRef(neW);
+ Cudd_RecursiveDeref(dd,old);
+ old = neW;
+ }
+
+#ifdef DD_DEBUG
+ /* Test. */
+ if (Cudd_bddLeq(dd,old,f)) {
+ cuddDeref(old);
+ } else {
+ Cudd_RecursiveDeref(dd,old);
+ old = NULL;
+ }
+#else
+ cuddDeref(old);
+#endif
+
+ FREE(string);
+ FREE(indices);
+ return(old);
+
+} /* end of Cudd_bddPickOneMinterm */
+
+
+/**Function********************************************************************
+
+ Synopsis [Picks k on-set minterms evenly distributed from given DD.]
+
+ Description [Picks k on-set minterms evenly distributed from given DD.
+ The minterms are in terms of <code>vars</code>. The array
+ <code>vars</code> should contain at least all variables in the
+ support of <code>f</code>; if this condition is not met the minterms
+ built by this procedure may not be contained in
+ <code>f</code>. Builds an array of BDDs for the minterms and returns a
+ pointer to it if successful; NULL otherwise. There are three reasons
+ why the procedure may fail:
+ <ul>
+ <li> It may run out of memory;
+ <li> the function <code>f</code> may be the constant 0;
+ <li> the minterms may not be contained in <code>f</code>.
+ </ul>]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddPickOneMinterm Cudd_bddPickOneCube]
+
+******************************************************************************/
+DdNode **
+Cudd_bddPickArbitraryMinterms(
+ DdManager * dd /* manager */,
+ DdNode * f /* function from which to pick k minterms */,
+ DdNode ** vars /* array of variables */,
+ int n /* size of <code>vars</code> */,
+ int k /* number of minterms to find */)
+{
+ char **string;
+ int i, j, l, size;
+ int *indices;
+ int result;
+ DdNode **old, *neW;
+ double minterms;
+ char *saveString;
+ int saveFlag, savePoint, isSame;
+
+ minterms = Cudd_CountMinterm(dd,f,n);
+ if ((double)k > minterms) {
+ return(NULL);
+ }
+
+ size = dd->size;
+ string = ALLOC(char *, k);
+ if (string == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < k; i++) {
+ string[i] = ALLOC(char, size + 1);
+ if (string[i] == NULL) {
+ for (j = 0; j < i; j++)
+ FREE(string[i]);
+ FREE(string);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (j = 0; j < size; j++) string[i][j] = '2';
+ string[i][size] = '\0';
+ }
+ indices = ALLOC(int,n);
+ if (indices == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ for (i = 0; i < k; i++)
+ FREE(string[i]);
+ FREE(string);
+ return(NULL);
+ }
+
+ for (i = 0; i < n; i++) {
+ indices[i] = vars[i]->index;
+ }
+
+ result = ddPickArbitraryMinterms(dd,f,n,k,string);
+ if (result == 0) {
+ for (i = 0; i < k; i++)
+ FREE(string[i]);
+ FREE(string);
+ FREE(indices);
+ return(NULL);
+ }
+
+ old = ALLOC(DdNode *, k);
+ if (old == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ for (i = 0; i < k; i++)
+ FREE(string[i]);
+ FREE(string);
+ FREE(indices);
+ return(NULL);
+ }
+ saveString = ALLOC(char, size + 1);
+ if (saveString == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ for (i = 0; i < k; i++)
+ FREE(string[i]);
+ FREE(string);
+ FREE(indices);
+ FREE(old);
+ return(NULL);
+ }
+ saveFlag = 0;
+
+ /* Build result BDD array. */
+ for (i = 0; i < k; i++) {
+ isSame = 0;
+ if (!saveFlag) {
+ for (j = i + 1; j < k; j++) {
+ if (strcmp(string[i], string[j]) == 0) {
+ savePoint = i;
+ strcpy(saveString, string[i]);
+ saveFlag = 1;
+ break;
+ }
+ }
+ } else {
+ if (strcmp(string[i], saveString) == 0) {
+ isSame = 1;
+ } else {
+ saveFlag = 0;
+ for (j = i + 1; j < k; j++) {
+ if (strcmp(string[i], string[j]) == 0) {
+ savePoint = i;
+ strcpy(saveString, string[i]);
+ saveFlag = 1;
+ break;
+ }
+ }
+ }
+ }
+ /* Randomize choice for don't cares. */
+ for (j = 0; j < n; j++) {
+ if (string[i][indices[j]] == '2')
+ string[i][indices[j]] = (Cudd_Random() & 0x20) ? '1' : '0';
+ }
+
+ while (isSame) {
+ isSame = 0;
+ for (j = savePoint; j < i; j++) {
+ if (strcmp(string[i], string[j]) == 0) {
+ isSame = 1;
+ break;
+ }
+ }
+ if (isSame) {
+ strcpy(string[i], saveString);
+ /* Randomize choice for don't cares. */
+ for (j = 0; j < n; j++) {
+ if (string[i][indices[j]] == '2')
+ string[i][indices[j]] = (Cudd_Random() & 0x20) ?
+ '1' : '0';
+ }
+ }
+ }
+
+ old[i] = Cudd_ReadOne(dd);
+ cuddRef(old[i]);
+
+ for (j = 0; j < n; j++) {
+ if (string[i][indices[j]] == '0') {
+ neW = Cudd_bddAnd(dd,old[i],Cudd_Not(vars[j]));
+ } else {
+ neW = Cudd_bddAnd(dd,old[i],vars[j]);
+ }
+ if (neW == NULL) {
+ FREE(saveString);
+ for (l = 0; l < k; l++)
+ FREE(string[l]);
+ FREE(string);
+ FREE(indices);
+ for (l = 0; l <= i; l++)
+ Cudd_RecursiveDeref(dd,old[l]);
+ FREE(old);
+ return(NULL);
+ }
+ cuddRef(neW);
+ Cudd_RecursiveDeref(dd,old[i]);
+ old[i] = neW;
+ }
+
+ /* Test. */
+ if (!Cudd_bddLeq(dd,old[i],f)) {
+ FREE(saveString);
+ for (l = 0; l < k; l++)
+ FREE(string[l]);
+ FREE(string);
+ FREE(indices);
+ for (l = 0; l <= i; l++)
+ Cudd_RecursiveDeref(dd,old[l]);
+ FREE(old);
+ return(NULL);
+ }
+ }
+
+ FREE(saveString);
+ for (i = 0; i < k; i++) {
+ cuddDeref(old[i]);
+ FREE(string[i]);
+ }
+ FREE(string);
+ FREE(indices);
+ return(old);
+
+} /* end of Cudd_bddPickArbitraryMinterms */
+
+
+/**Function********************************************************************
+
+ Synopsis [Extracts a subset from a BDD.]
+
+ Description [Extracts a subset from a BDD in the following procedure.
+ 1. Compute the weight for each mask variable by counting the number of
+ minterms for both positive and negative cofactors of the BDD with
+ respect to each mask variable. (weight = #positive - #negative)
+ 2. Find a representative cube of the BDD by using the weight. From the
+ top variable of the BDD, for each variable, if the weight is greater
+ than 0.0, choose THEN branch, othereise ELSE branch, until meeting
+ the constant 1.
+ 3. Quantify out the variables not in maskVars from the representative
+ cube and if a variable in maskVars is don't care, replace the
+ variable with a constant(1 or 0) depending on the weight.
+ 4. Make a subset of the BDD by multiplying with the modified cube.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_SubsetWithMaskVars(
+ DdManager * dd /* manager */,
+ DdNode * f /* function from which to pick a cube */,
+ DdNode ** vars /* array of variables */,
+ int nvars /* size of <code>vars</code> */,
+ DdNode ** maskVars /* array of variables */,
+ int mvars /* size of <code>maskVars</code> */)
+{
+ double *weight;
+ char *string;
+ int i, size;
+ int *indices, *mask;
+ int result;
+ DdNode *zero, *cube, *newCube, *subset;
+ DdNode *cof;
+
+ DdNode *support;
+ support = Cudd_Support(dd,f);
+ cuddRef(support);
+ Cudd_RecursiveDeref(dd,support);
+
+ zero = Cudd_Not(dd->one);
+ size = dd->size;
+
+ weight = ALLOC(double,size);
+ if (weight == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < size; i++) {
+ weight[i] = 0.0;
+ }
+ for (i = 0; i < mvars; i++) {
+ cof = Cudd_Cofactor(dd, f, maskVars[i]);
+ cuddRef(cof);
+ weight[i] = Cudd_CountMinterm(dd, cof, nvars);
+ Cudd_RecursiveDeref(dd,cof);
+
+ cof = Cudd_Cofactor(dd, f, Cudd_Not(maskVars[i]));
+ cuddRef(cof);
+ weight[i] -= Cudd_CountMinterm(dd, cof, nvars);
+ Cudd_RecursiveDeref(dd,cof);
+ }
+
+ string = ALLOC(char, size + 1);
+ if (string == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ mask = ALLOC(int, size);
+ if (mask == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ FREE(string);
+ return(NULL);
+ }
+ for (i = 0; i < size; i++) {
+ string[i] = '2';
+ mask[i] = 0;
+ }
+ string[size] = '\0';
+ indices = ALLOC(int,nvars);
+ if (indices == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ FREE(string);
+ FREE(mask);
+ return(NULL);
+ }
+ for (i = 0; i < nvars; i++) {
+ indices[i] = vars[i]->index;
+ }
+
+ result = ddPickRepresentativeCube(dd,f,nvars,weight,string);
+ if (result == 0) {
+ FREE(string);
+ FREE(mask);
+ FREE(indices);
+ return(NULL);
+ }
+
+ cube = Cudd_ReadOne(dd);
+ cuddRef(cube);
+ zero = Cudd_Not(Cudd_ReadOne(dd));
+ for (i = 0; i < nvars; i++) {
+ if (string[indices[i]] == '0') {
+ newCube = Cudd_bddIte(dd,cube,Cudd_Not(vars[i]),zero);
+ } else if (string[indices[i]] == '1') {
+ newCube = Cudd_bddIte(dd,cube,vars[i],zero);
+ } else
+ continue;
+ if (newCube == NULL) {
+ FREE(string);
+ FREE(mask);
+ FREE(indices);
+ Cudd_RecursiveDeref(dd,cube);
+ return(NULL);
+ }
+ cuddRef(newCube);
+ Cudd_RecursiveDeref(dd,cube);
+ cube = newCube;
+ }
+ Cudd_RecursiveDeref(dd,cube);
+
+ for (i = 0; i < mvars; i++) {
+ mask[maskVars[i]->index] = 1;
+ }
+ for (i = 0; i < nvars; i++) {
+ if (mask[indices[i]]) {
+ if (string[indices[i]] == '2') {
+ if (weight[indices[i]] >= 0.0)
+ string[indices[i]] = '1';
+ else
+ string[indices[i]] = '0';
+ }
+ } else {
+ string[indices[i]] = '2';
+ }
+ }
+
+ cube = Cudd_ReadOne(dd);
+ cuddRef(cube);
+ zero = Cudd_Not(Cudd_ReadOne(dd));
+
+ /* Build result BDD. */
+ for (i = 0; i < nvars; i++) {
+ if (string[indices[i]] == '0') {
+ newCube = Cudd_bddIte(dd,cube,Cudd_Not(vars[i]),zero);
+ } else if (string[indices[i]] == '1') {
+ newCube = Cudd_bddIte(dd,cube,vars[i],zero);
+ } else
+ continue;
+ if (newCube == NULL) {
+ FREE(string);
+ FREE(mask);
+ FREE(indices);
+ Cudd_RecursiveDeref(dd,cube);
+ return(NULL);
+ }
+ cuddRef(newCube);
+ Cudd_RecursiveDeref(dd,cube);
+ cube = newCube;
+ }
+
+ subset = Cudd_bddAnd(dd,f,cube);
+ cuddRef(subset);
+ Cudd_RecursiveDeref(dd,cube);
+
+ /* Test. */
+ if (Cudd_bddLeq(dd,subset,f)) {
+ cuddDeref(subset);
+ } else {
+ Cudd_RecursiveDeref(dd,subset);
+ subset = NULL;
+ }
+
+ FREE(string);
+ FREE(mask);
+ FREE(indices);
+ FREE(weight);
+ return(subset);
+
+} /* end of Cudd_SubsetWithMaskVars */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the first cube of a decision diagram.]
+
+ Description [Defines an iterator on the onset of a decision diagram
+ and finds its first cube. Returns a generator that contains the
+ information necessary to continue the enumeration if successful; NULL
+ otherwise.<p>
+ A cube is represented as an array of literals, which are integers in
+ {0, 1, 2}; 0 represents a complemented literal, 1 represents an
+ uncomplemented literal, and 2 stands for don't care. The enumeration
+ produces a disjoint cover of the function associated with the diagram.
+ The size of the array equals the number of variables in the manager at
+ the time Cudd_FirstCube is called.<p>
+ For each cube, a value is also returned. This value is always 1 for a
+ BDD, while it may be different from 1 for an ADD.
+ For BDDs, the offset is the set of cubes whose value is the logical zero.
+ For ADDs, the offset is the set of cubes whose value is the
+ background value. The cubes of the offset are not enumerated.]
+
+ SideEffects [The first cube and its value are returned as side effects.]
+
+ SeeAlso [Cudd_ForeachCube Cudd_NextCube Cudd_GenFree Cudd_IsGenEmpty
+ Cudd_FirstNode]
+
+******************************************************************************/
+DdGen *
+Cudd_FirstCube(
+ DdManager * dd,
+ DdNode * f,
+ int ** cube,
+ CUDD_VALUE_TYPE * value)
+{
+ DdGen *gen;
+ DdNode *top, *treg, *next, *nreg, *prev, *preg;
+ int i;
+ int nvars;
+
+ /* Sanity Check. */
+ if (dd == NULL || f == NULL) return(NULL);
+
+ /* Allocate generator an initialize it. */
+ gen = ALLOC(DdGen,1);
+ if (gen == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+
+ gen->manager = dd;
+ gen->type = CUDD_GEN_CUBES;
+ gen->status = CUDD_GEN_EMPTY;
+ gen->gen.cubes.cube = NULL;
+ gen->gen.cubes.value = DD_ZERO_VAL;
+ gen->stack.sp = 0;
+ gen->stack.stack = NULL;
+ gen->node = NULL;
+
+ nvars = dd->size;
+ gen->gen.cubes.cube = ALLOC(int,nvars);
+ if (gen->gen.cubes.cube == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ FREE(gen);
+ return(NULL);
+ }
+ for (i = 0; i < nvars; i++) gen->gen.cubes.cube[i] = 2;
+
+ /* The maximum stack depth is one plus the number of variables.
+ ** because a path may have nodes at all levels, including the
+ ** constant level.
+ */
+ gen->stack.stack = ALLOC(DdNode *, nvars+1);
+ if (gen->stack.stack == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ FREE(gen->gen.cubes.cube);
+ FREE(gen);
+ return(NULL);
+ }
+ for (i = 0; i <= nvars; i++) gen->stack.stack[i] = NULL;
+
+ /* Find the first cube of the onset. */
+ gen->stack.stack[gen->stack.sp] = f; gen->stack.sp++;
+
+ while (1) {
+ top = gen->stack.stack[gen->stack.sp-1];
+ treg = Cudd_Regular(top);
+ if (!cuddIsConstant(treg)) {
+ /* Take the else branch first. */
+ gen->gen.cubes.cube[treg->index] = 0;
+ next = cuddE(treg);
+ if (top != treg) next = Cudd_Not(next);
+ gen->stack.stack[gen->stack.sp] = next; gen->stack.sp++;
+ } else if (top == Cudd_Not(DD_ONE(dd)) || top == dd->background) {
+ /* Backtrack */
+ while (1) {
+ if (gen->stack.sp == 1) {
+ /* The current node has no predecessor. */
+ gen->status = CUDD_GEN_EMPTY;
+ gen->stack.sp--;
+ goto done;
+ }
+ prev = gen->stack.stack[gen->stack.sp-2];
+ preg = Cudd_Regular(prev);
+ nreg = cuddT(preg);
+ if (prev != preg) {next = Cudd_Not(nreg);} else {next = nreg;}
+ if (next != top) { /* follow the then branch next */
+ gen->gen.cubes.cube[preg->index] = 1;
+ gen->stack.stack[gen->stack.sp-1] = next;
+ break;
+ }
+ /* Pop the stack and try again. */
+ gen->gen.cubes.cube[preg->index] = 2;
+ gen->stack.sp--;
+ top = gen->stack.stack[gen->stack.sp-1];
+ treg = Cudd_Regular(top);
+ }
+ } else {
+ gen->status = CUDD_GEN_NONEMPTY;
+ gen->gen.cubes.value = cuddV(top);
+ goto done;
+ }
+ }
+
+done:
+ *cube = gen->gen.cubes.cube;
+ *value = gen->gen.cubes.value;
+ return(gen);
+
+} /* end of Cudd_FirstCube */
+
+
+/**Function********************************************************************
+
+ Synopsis [Generates the next cube of a decision diagram onset.]
+
+ Description [Generates the next cube of a decision diagram onset,
+ using generator gen. Returns 0 if the enumeration is completed; 1
+ otherwise.]
+
+ SideEffects [The cube and its value are returned as side effects. The
+ generator is modified.]
+
+ SeeAlso [Cudd_ForeachCube Cudd_FirstCube Cudd_GenFree Cudd_IsGenEmpty
+ Cudd_NextNode]
+
+******************************************************************************/
+int
+Cudd_NextCube(
+ DdGen * gen,
+ int ** cube,
+ CUDD_VALUE_TYPE * value)
+{
+ DdNode *top, *treg, *next, *nreg, *prev, *preg;
+ DdManager *dd = gen->manager;
+
+ /* Backtrack from previously reached terminal node. */
+ while (1) {
+ if (gen->stack.sp == 1) {
+ /* The current node has no predecessor. */
+ gen->status = CUDD_GEN_EMPTY;
+ gen->stack.sp--;
+ goto done;
+ }
+ top = gen->stack.stack[gen->stack.sp-1];
+ treg = Cudd_Regular(top);
+ prev = gen->stack.stack[gen->stack.sp-2];
+ preg = Cudd_Regular(prev);
+ nreg = cuddT(preg);
+ if (prev != preg) {next = Cudd_Not(nreg);} else {next = nreg;}
+ if (next != top) { /* follow the then branch next */
+ gen->gen.cubes.cube[preg->index] = 1;
+ gen->stack.stack[gen->stack.sp-1] = next;
+ break;
+ }
+ /* Pop the stack and try again. */
+ gen->gen.cubes.cube[preg->index] = 2;
+ gen->stack.sp--;
+ }
+
+ while (1) {
+ top = gen->stack.stack[gen->stack.sp-1];
+ treg = Cudd_Regular(top);
+ if (!cuddIsConstant(treg)) {
+ /* Take the else branch first. */
+ gen->gen.cubes.cube[treg->index] = 0;
+ next = cuddE(treg);
+ if (top != treg) next = Cudd_Not(next);
+ gen->stack.stack[gen->stack.sp] = next; gen->stack.sp++;
+ } else if (top == Cudd_Not(DD_ONE(dd)) || top == dd->background) {
+ /* Backtrack */
+ while (1) {
+ if (gen->stack.sp == 1) {
+ /* The current node has no predecessor. */
+ gen->status = CUDD_GEN_EMPTY;
+ gen->stack.sp--;
+ goto done;
+ }
+ prev = gen->stack.stack[gen->stack.sp-2];
+ preg = Cudd_Regular(prev);
+ nreg = cuddT(preg);
+ if (prev != preg) {next = Cudd_Not(nreg);} else {next = nreg;}
+ if (next != top) { /* follow the then branch next */
+ gen->gen.cubes.cube[preg->index] = 1;
+ gen->stack.stack[gen->stack.sp-1] = next;
+ break;
+ }
+ /* Pop the stack and try again. */
+ gen->gen.cubes.cube[preg->index] = 2;
+ gen->stack.sp--;
+ top = gen->stack.stack[gen->stack.sp-1];
+ treg = Cudd_Regular(top);
+ }
+ } else {
+ gen->status = CUDD_GEN_NONEMPTY;
+ gen->gen.cubes.value = cuddV(top);
+ goto done;
+ }
+ }
+
+done:
+ if (gen->status == CUDD_GEN_EMPTY) return(0);
+ *cube = gen->gen.cubes.cube;
+ *value = gen->gen.cubes.value;
+ return(1);
+
+} /* end of Cudd_NextCube */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the cube of an array of BDD variables.]
+
+ Description [Computes the cube of an array of BDD variables. If
+ non-null, the phase argument indicates which literal of each
+ variable should appear in the cube. If phase\[i\] is nonzero, then the
+ positive literal is used. If phase is NULL, the cube is positive unate.
+ Returns a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addComputeCube Cudd_IndicesToCube Cudd_CubeArrayToBdd]
+
+******************************************************************************/
+DdNode *
+Cudd_bddComputeCube(
+ DdManager * dd,
+ DdNode ** vars,
+ int * phase,
+ int n)
+{
+ DdNode *cube;
+ DdNode *fn;
+ int i;
+
+ cube = DD_ONE(dd);
+ cuddRef(cube);
+
+ for (i = n - 1; i >= 0; i--) {
+ if (phase == NULL || phase[i] != 0) {
+ fn = Cudd_bddAnd(dd,vars[i],cube);
+ } else {
+ fn = Cudd_bddAnd(dd,Cudd_Not(vars[i]),cube);
+ }
+ if (fn == NULL) {
+ Cudd_RecursiveDeref(dd,cube);
+ return(NULL);
+ }
+ cuddRef(fn);
+ Cudd_RecursiveDeref(dd,cube);
+ cube = fn;
+ }
+ cuddDeref(cube);
+
+ return(cube);
+
+} /* end of Cudd_bddComputeCube */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the cube of an array of ADD variables.]
+
+ Description [Computes the cube of an array of ADD variables. If
+ non-null, the phase argument indicates which literal of each
+ variable should appear in the cube. If phase\[i\] is nonzero, then the
+ positive literal is used. If phase is NULL, the cube is positive unate.
+ Returns a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_bddComputeCube]
+
+******************************************************************************/
+DdNode *
+Cudd_addComputeCube(
+ DdManager * dd,
+ DdNode ** vars,
+ int * phase,
+ int n)
+{
+ DdNode *cube, *zero;
+ DdNode *fn;
+ int i;
+
+ cube = DD_ONE(dd);
+ cuddRef(cube);
+ zero = DD_ZERO(dd);
+
+ for (i = n - 1; i >= 0; i--) {
+ if (phase == NULL || phase[i] != 0) {
+ fn = Cudd_addIte(dd,vars[i],cube,zero);
+ } else {
+ fn = Cudd_addIte(dd,vars[i],zero,cube);
+ }
+ if (fn == NULL) {
+ Cudd_RecursiveDeref(dd,cube);
+ return(NULL);
+ }
+ cuddRef(fn);
+ Cudd_RecursiveDeref(dd,cube);
+ cube = fn;
+ }
+ cuddDeref(cube);
+
+ return(cube);
+
+} /* end of Cudd_addComputeCube */
+
+
+/**Function********************************************************************
+
+ Synopsis [Builds the BDD of a cube from a positional array.]
+
+ Description [Builds a cube from a positional array. The array must
+ have one integer entry for each BDD variable. If the i-th entry is
+ 1, the variable of index i appears in true form in the cube; If the
+ i-th entry is 0, the variable of index i appears complemented in the
+ cube; otherwise the variable does not appear in the cube. Returns a
+ pointer to the BDD for the cube if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddComputeCube Cudd_IndicesToCube Cudd_BddToCubeArray]
+
+******************************************************************************/
+DdNode *
+Cudd_CubeArrayToBdd(
+ DdManager *dd,
+ int *array)
+{
+ DdNode *cube, *var, *tmp;
+ int i;
+ int size = Cudd_ReadSize(dd);
+
+ cube = DD_ONE(dd);
+ cuddRef(cube);
+ for (i = size - 1; i >= 0; i--) {
+ if ((array[i] & ~1) == 0) {
+ var = Cudd_bddIthVar(dd,i);
+ tmp = Cudd_bddAnd(dd,cube,Cudd_NotCond(var,array[i]==0));
+ if (tmp == NULL) {
+ Cudd_RecursiveDeref(dd,cube);
+ return(NULL);
+ }
+ cuddRef(tmp);
+ Cudd_RecursiveDeref(dd,cube);
+ cube = tmp;
+ }
+ }
+ cuddDeref(cube);
+ return(cube);
+
+} /* end of Cudd_CubeArrayToBdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Builds a positional array from the BDD of a cube.]
+
+ Description [Builds a positional array from the BDD of a cube.
+ Array must have one entry for each BDD variable. The positional
+ array has 1 in i-th position if the variable of index i appears in
+ true form in the cube; it has 0 in i-th position if the variable of
+ index i appears in complemented form in the cube; finally, it has 2
+ in i-th position if the variable of index i does not appear in the
+ cube. Returns 1 if successful (the BDD is indeed a cube); 0
+ otherwise.]
+
+ SideEffects [The result is in the array passed by reference.]
+
+ SeeAlso [Cudd_CubeArrayToBdd]
+
+******************************************************************************/
+int
+Cudd_BddToCubeArray(
+ DdManager *dd,
+ DdNode *cube,
+ int *array)
+{
+ DdNode *scan, *t, *e;
+ int i;
+ int size = Cudd_ReadSize(dd);
+ DdNode *zero = Cudd_Not(DD_ONE(dd));
+
+ for (i = size-1; i >= 0; i--) {
+ array[i] = 2;
+ }
+ scan = cube;
+ while (!Cudd_IsConstant(scan)) {
+ int index = Cudd_Regular(scan)->index;
+ cuddGetBranches(scan,&t,&e);
+ if (t == zero) {
+ array[index] = 0;
+ scan = e;
+ } else if (e == zero) {
+ array[index] = 1;
+ scan = t;
+ } else {
+ return(0); /* cube is not a cube */
+ }
+ }
+ if (scan == zero) {
+ return(0);
+ } else {
+ return(1);
+ }
+
+} /* end of Cudd_BddToCubeArray */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the first node of a decision diagram.]
+
+ Description [Defines an iterator on the nodes of a decision diagram
+ and finds its first node. Returns a generator that contains the
+ information necessary to continue the enumeration if successful; NULL
+ otherwise.]
+
+ SideEffects [The first node is returned as a side effect.]
+
+ SeeAlso [Cudd_ForeachNode Cudd_NextNode Cudd_GenFree Cudd_IsGenEmpty
+ Cudd_FirstCube]
+
+******************************************************************************/
+DdGen *
+Cudd_FirstNode(
+ DdManager * dd,
+ DdNode * f,
+ DdNode ** node)
+{
+ DdGen *gen;
+ int retval;
+
+ /* Sanity Check. */
+ if (dd == NULL || f == NULL) return(NULL);
+
+ /* Allocate generator an initialize it. */
+ gen = ALLOC(DdGen,1);
+ if (gen == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+
+ gen->manager = dd;
+ gen->type = CUDD_GEN_NODES;
+ gen->status = CUDD_GEN_EMPTY;
+ gen->gen.nodes.visited = NULL;
+ gen->gen.nodes.stGen = NULL;
+ gen->stack.sp = 0;
+ gen->stack.stack = NULL;
+ gen->node = NULL;
+
+ gen->gen.nodes.visited = st_init_table(st_ptrcmp,st_ptrhash);
+ if (gen->gen.nodes.visited == NULL) {
+ FREE(gen);
+ return(NULL);
+ }
+
+ /* Collect all the nodes in a st table for later perusal. */
+ retval = cuddCollectNodes(Cudd_Regular(f),gen->gen.nodes.visited);
+ if (retval == 0) {
+ st_free_table(gen->gen.nodes.visited);
+ FREE(gen);
+ return(NULL);
+ }
+
+ /* Initialize the st table generator. */
+ gen->gen.nodes.stGen = st_init_gen(gen->gen.nodes.visited);
+ if (gen->gen.nodes.stGen == NULL) {
+ st_free_table(gen->gen.nodes.visited);
+ FREE(gen);
+ return(NULL);
+ }
+
+ /* Find the first node. */
+ retval = st_gen(gen->gen.nodes.stGen, (char **) &(gen->node), NULL);
+ if (retval != 0) {
+ gen->status = CUDD_GEN_NONEMPTY;
+ *node = gen->node;
+ }
+
+ return(gen);
+
+} /* end of Cudd_FirstNode */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the next node of a decision diagram.]
+
+ Description [Finds the node of a decision diagram, using generator
+ gen. Returns 0 if the enumeration is completed; 1 otherwise.]
+
+ SideEffects [The next node is returned as a side effect.]
+
+ SeeAlso [Cudd_ForeachNode Cudd_FirstNode Cudd_GenFree Cudd_IsGenEmpty
+ Cudd_NextCube]
+
+******************************************************************************/
+int
+Cudd_NextNode(
+ DdGen * gen,
+ DdNode ** node)
+{
+ int retval;
+
+ /* Find the next node. */
+ retval = st_gen(gen->gen.nodes.stGen, (char **) &(gen->node), NULL);
+ if (retval == 0) {
+ gen->status = CUDD_GEN_EMPTY;
+ } else {
+ *node = gen->node;
+ }
+
+ return(retval);
+
+} /* end of Cudd_NextNode */
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees a CUDD generator.]
+
+ Description [Frees a CUDD generator. Always returns 0, so that it can
+ be used in mis-like foreach constructs.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ForeachCube Cudd_ForeachNode Cudd_FirstCube Cudd_NextCube
+ Cudd_FirstNode Cudd_NextNode Cudd_IsGenEmpty]
+
+******************************************************************************/
+int
+Cudd_GenFree(
+ DdGen * gen)
+{
+
+ if (gen == NULL) return(0);
+ switch (gen->type) {
+ case CUDD_GEN_CUBES:
+ case CUDD_GEN_ZDD_PATHS:
+ FREE(gen->gen.cubes.cube);
+ FREE(gen->stack.stack);
+ break;
+ case CUDD_GEN_NODES:
+ st_free_gen(gen->gen.nodes.stGen);
+ st_free_table(gen->gen.nodes.visited);
+ break;
+ default:
+ return(0);
+ }
+ FREE(gen);
+ return(0);
+
+} /* end of Cudd_GenFree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Queries the status of a generator.]
+
+ Description [Queries the status of a generator. Returns 1 if the
+ generator is empty or NULL; 0 otherswise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_ForeachCube Cudd_ForeachNode Cudd_FirstCube Cudd_NextCube
+ Cudd_FirstNode Cudd_NextNode Cudd_GenFree]
+
+******************************************************************************/
+int
+Cudd_IsGenEmpty(
+ DdGen * gen)
+{
+ if (gen == NULL) return(1);
+ return(gen->status == CUDD_GEN_EMPTY);
+
+} /* end of Cudd_IsGenEmpty */
+
+
+/**Function********************************************************************
+
+ Synopsis [Builds a cube of BDD variables from an array of indices.]
+
+ Description [Builds a cube of BDD variables from an array of indices.
+ Returns a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddComputeCube Cudd_CubeArrayToBdd]
+
+******************************************************************************/
+DdNode *
+Cudd_IndicesToCube(
+ DdManager * dd,
+ int * array,
+ int n)
+{
+ DdNode *cube, *tmp;
+ int i;
+
+ cube = DD_ONE(dd);
+ cuddRef(cube);
+ for (i = n - 1; i >= 0; i--) {
+ tmp = Cudd_bddAnd(dd,Cudd_bddIthVar(dd,array[i]),cube);
+ if (tmp == NULL) {
+ Cudd_RecursiveDeref(dd,cube);
+ return(NULL);
+ }
+ cuddRef(tmp);
+ Cudd_RecursiveDeref(dd,cube);
+ cube = tmp;
+ }
+
+ cuddDeref(cube);
+ return(cube);
+
+} /* end of Cudd_IndicesToCube */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints the package version number.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+Cudd_PrintVersion(
+ FILE * fp)
+{
+ (void) fprintf(fp, "%s\n", CUDD_VERSION);
+
+} /* end of Cudd_PrintVersion */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the average distance between adjacent nodes.]
+
+ Description [Computes the average distance between adjacent nodes in
+ the manager. Adjacent nodes are node pairs such that the second node
+ is the then child, else child, or next node in the collision list.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+double
+Cudd_AverageDistance(
+ DdManager * dd)
+{
+ double tetotal, nexttotal;
+ double tesubtotal, nextsubtotal;
+ double temeasured, nextmeasured;
+ int i, j;
+ int slots, nvars;
+ long diff;
+ DdNode *scan;
+ DdNodePtr *nodelist;
+ DdNode *sentinel = &(dd->sentinel);
+
+ nvars = dd->size;
+ if (nvars == 0) return(0.0);
+
+ /* Initialize totals. */
+ tetotal = 0.0;
+ nexttotal = 0.0;
+ temeasured = 0.0;
+ nextmeasured = 0.0;
+
+ /* Scan the variable subtables. */
+ for (i = 0; i < nvars; i++) {
+ nodelist = dd->subtables[i].nodelist;
+ tesubtotal = 0.0;
+ nextsubtotal = 0.0;
+ slots = dd->subtables[i].slots;
+ for (j = 0; j < slots; j++) {
+ scan = nodelist[j];
+ while (scan != sentinel) {
+ diff = (long) scan - (long) cuddT(scan);
+ tesubtotal += (double) ddAbs(diff);
+ diff = (long) scan - (long) Cudd_Regular(cuddE(scan));
+ tesubtotal += (double) ddAbs(diff);
+ temeasured += 2.0;
+ if (scan->next != NULL) {
+ diff = (long) scan - (long) scan->next;
+ nextsubtotal += (double) ddAbs(diff);
+ nextmeasured += 1.0;
+ }
+ scan = scan->next;
+ }
+ }
+ tetotal += tesubtotal;
+ nexttotal += nextsubtotal;
+ }
+
+ /* Scan the constant table. */
+ nodelist = dd->constants.nodelist;
+ nextsubtotal = 0.0;
+ slots = dd->constants.slots;
+ for (j = 0; j < slots; j++) {
+ scan = nodelist[j];
+ while (scan != NULL) {
+ if (scan->next != NULL) {
+ diff = (long) scan - (long) scan->next;
+ nextsubtotal += (double) ddAbs(diff);
+ nextmeasured += 1.0;
+ }
+ scan = scan->next;
+ }
+ }
+ nexttotal += nextsubtotal;
+
+ return((tetotal + nexttotal) / (temeasured + nextmeasured));
+
+} /* end of Cudd_AverageDistance */
+
+
+/**Function********************************************************************
+
+ Synopsis [Portable random number generator.]
+
+ Description [Portable number generator based on ran2 from "Numerical
+ Recipes in C." It is a long period (> 2 * 10^18) random number generator
+ of L'Ecuyer with Bays-Durham shuffle. Returns a long integer uniformly
+ distributed between 0 and 2147483561 (inclusive of the endpoint values).
+ The random generator can be explicitly initialized by calling
+ Cudd_Srandom. If no explicit initialization is performed, then the
+ seed 1 is assumed.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Srandom]
+
+******************************************************************************/
+long
+Cudd_Random(
+ )
+{
+ int i; /* index in the shuffle table */
+ long int w; /* work variable */
+
+ /* cuddRand == 0 if the geneartor has not been initialized yet. */
+ if (cuddRand == 0) Cudd_Srandom(1);
+
+ /* Compute cuddRand = (cuddRand * LEQA1) % MODULUS1 avoiding
+ ** overflows by Schrage's method.
+ */
+ w = cuddRand / LEQQ1;
+ cuddRand = LEQA1 * (cuddRand - w * LEQQ1) - w * LEQR1;
+ cuddRand += (cuddRand < 0) * MODULUS1;
+
+ /* Compute cuddRand2 = (cuddRand2 * LEQA2) % MODULUS2 avoiding
+ ** overflows by Schrage's method.
+ */
+ w = cuddRand2 / LEQQ2;
+ cuddRand2 = LEQA2 * (cuddRand2 - w * LEQQ2) - w * LEQR2;
+ cuddRand2 += (cuddRand2 < 0) * MODULUS2;
+
+ /* cuddRand is shuffled with the Bays-Durham algorithm.
+ ** shuffleSelect and cuddRand2 are combined to generate the output.
+ */
+
+ /* Pick one element from the shuffle table; "i" will be in the range
+ ** from 0 to STAB_SIZE-1.
+ */
+ i = (int) (shuffleSelect / STAB_DIV);
+ /* Mix the element of the shuffle table with the current iterate of
+ ** the second sub-generator, and replace the chosen element of the
+ ** shuffle table with the current iterate of the first sub-generator.
+ */
+ shuffleSelect = shuffleTable[i] - cuddRand2;
+ shuffleTable[i] = cuddRand;
+ shuffleSelect += (shuffleSelect < 1) * (MODULUS1 - 1);
+ /* Since shuffleSelect != 0, and we want to be able to return 0,
+ ** here we subtract 1 before returning.
+ */
+ return(shuffleSelect - 1);
+
+} /* end of Cudd_Random */
+
+
+/**Function********************************************************************
+
+ Synopsis [Initializer for the portable random number generator.]
+
+ Description [Initializer for the portable number generator based on
+ ran2 in "Numerical Recipes in C." The input is the seed for the
+ generator. If it is negative, its absolute value is taken as seed.
+ If it is 0, then 1 is taken as seed. The initialized sets up the two
+ recurrences used to generate a long-period stream, and sets up the
+ shuffle table.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_Random]
+
+******************************************************************************/
+void
+Cudd_Srandom(
+ long seed)
+{
+ int i;
+
+ if (seed < 0) cuddRand = -seed;
+ else if (seed == 0) cuddRand = 1;
+ else cuddRand = seed;
+ cuddRand2 = cuddRand;
+ /* Load the shuffle table (after 11 warm-ups). */
+ for (i = 0; i < STAB_SIZE + 11; i++) {
+ long int w;
+ w = cuddRand / LEQQ1;
+ cuddRand = LEQA1 * (cuddRand - w * LEQQ1) - w * LEQR1;
+ cuddRand += (cuddRand < 0) * MODULUS1;
+ shuffleTable[i % STAB_SIZE] = cuddRand;
+ }
+ shuffleSelect = shuffleTable[1 % STAB_SIZE];
+
+} /* end of Cudd_Srandom */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the density of a BDD or ADD.]
+
+ Description [Computes the density of a BDD or ADD. The density is
+ the ratio of the number of minterms to the number of nodes. If 0 is
+ passed as number of variables, the number of variables existing in
+ the manager is used. Returns the density if successful; (double)
+ CUDD_OUT_OF_MEM otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_CountMinterm Cudd_DagSize]
+
+******************************************************************************/
+double
+Cudd_Density(
+ DdManager * dd /* manager */,
+ DdNode * f /* function whose density is sought */,
+ int nvars /* size of the support of f */)
+{
+ double minterms;
+ int nodes;
+ double density;
+
+ if (nvars == 0) nvars = dd->size;
+ minterms = Cudd_CountMinterm(dd,f,nvars);
+ if (minterms == (double) CUDD_OUT_OF_MEM) return(minterms);
+ nodes = Cudd_DagSize(f);
+ density = minterms / (double) nodes;
+ return(density);
+
+} /* end of Cudd_Density */
+
+
+/**Function********************************************************************
+
+ Synopsis [Warns that a memory allocation failed.]
+
+ Description [Warns that a memory allocation failed.
+ This function can be used as replacement of MMout_of_memory to prevent
+ the safe_mem functions of the util package from exiting when malloc
+ returns NULL. One possible use is in case of discretionary allocations;
+ for instance, the allocation of memory to enlarge the computed table.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+Cudd_OutOfMem(
+ long size /* size of the allocation that failed */)
+{
+ (void) fflush(stdout);
+ (void) fprintf(stderr, "\nunable to allocate %ld bytes\n", size);
+ return;
+
+} /* end of Cudd_OutOfMem */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints a DD to the standard output. One line per node is
+ printed.]
+
+ Description [Prints a DD to the standard output. One line per node is
+ printed. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_PrintDebug]
+
+******************************************************************************/
+int
+cuddP(
+ DdManager * dd,
+ DdNode * f)
+{
+ int retval;
+ st_table *table = st_init_table(st_ptrcmp,st_ptrhash);
+
+ if (table == NULL) return(0);
+
+ retval = dp2(dd,f,table);
+ st_free_table(table);
+ (void) fputc('\n',dd->out);
+ return(retval);
+
+} /* end of cuddP */
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees the memory used to store the minterm counts recorded
+ in the visited table.]
+
+ Description [Frees the memory used to store the minterm counts
+ recorded in the visited table. Returns ST_CONTINUE.]
+
+ SideEffects [None]
+
+******************************************************************************/
+enum st_retval
+cuddStCountfree(
+ char * key,
+ char * value,
+ char * arg)
+{
+ double *d;
+
+ d = (double *)value;
+ FREE(d);
+ return(ST_CONTINUE);
+
+} /* end of cuddStCountfree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Recursively collects all the nodes of a DD in a symbol
+ table.]
+
+ Description [Traverses the BDD f and collects all its nodes in a
+ symbol table. f is assumed to be a regular pointer and
+ cuddCollectNodes guarantees this assumption in the recursive calls.
+ Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddCollectNodes(
+ DdNode * f,
+ st_table * visited)
+{
+ DdNode *T, *E;
+ int retval;
+
+#ifdef DD_DEBUG
+ assert(!Cudd_IsComplement(f));
+#endif
+
+ /* If already visited, nothing to do. */
+ if (st_is_member(visited, (char *) f) == 1)
+ return(1);
+
+ /* Check for abnormal condition that should never happen. */
+ if (f == NULL)
+ return(0);
+
+ /* Mark node as visited. */
+ if (st_add_direct(visited, (char *) f, NULL) == ST_OUT_OF_MEM)
+ return(0);
+
+ /* Check terminal case. */
+ if (cuddIsConstant(f))
+ return(1);
+
+ /* Recursive calls. */
+ T = cuddT(f);
+ retval = cuddCollectNodes(T,visited);
+ if (retval != 1) return(retval);
+ E = Cudd_Regular(cuddE(f));
+ retval = cuddCollectNodes(E,visited);
+ return(retval);
+
+} /* end of cuddCollectNodes */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of cuddP.]
+
+ Description [Performs the recursive step of cuddP. Returns 1 in case
+ of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+dp2(
+ DdManager *dd,
+ DdNode * f,
+ st_table * t)
+{
+ DdNode *g, *n, *N;
+ int T,E;
+
+ if (f == NULL) {
+ return(0);
+ }
+ g = Cudd_Regular(f);
+ if (cuddIsConstant(g)) {
+#if SIZEOF_VOID_P == 8
+ (void) fprintf(dd->out,"ID = %c0x%lx\tvalue = %-9g\n", bang(f),
+ (unsigned long) g / (unsigned long) sizeof(DdNode),cuddV(g));
+#else
+ (void) fprintf(dd->out,"ID = %c0x%x\tvalue = %-9g\n", bang(f),
+ (unsigned) g / (unsigned) sizeof(DdNode),cuddV(g));
+#endif
+ return(1);
+ }
+ if (st_is_member(t,(char *) g) == 1) {
+ return(1);
+ }
+ if (st_add_direct(t,(char *) g,NULL) == ST_OUT_OF_MEM)
+ return(0);
+#ifdef DD_STATS
+#if SIZEOF_VOID_P == 8
+ (void) fprintf(dd->out,"ID = %c0x%lx\tindex = %d\tr = %d\t", bang(f),
+ (unsigned long) g / (unsigned long) sizeof(DdNode), g->index, g->ref);
+#else
+ (void) fprintf(dd->out,"ID = %c0x%x\tindex = %d\tr = %d\t", bang(f),
+ (unsigned) g / (unsigned) sizeof(DdNode),g->index,g->ref);
+#endif
+#else
+#if SIZEOF_VOID_P == 8
+ (void) fprintf(dd->out,"ID = %c0x%lx\tindex = %d\t", bang(f),
+ (unsigned long) g / (unsigned long) sizeof(DdNode),g->index);
+#else
+ (void) fprintf(dd->out,"ID = %c0x%x\tindex = %d\t", bang(f),
+ (unsigned) g / (unsigned) sizeof(DdNode),g->index);
+#endif
+#endif
+ n = cuddT(g);
+ if (cuddIsConstant(n)) {
+ (void) fprintf(dd->out,"T = %-9g\t",cuddV(n));
+ T = 1;
+ } else {
+#if SIZEOF_VOID_P == 8
+ (void) fprintf(dd->out,"T = 0x%lx\t",(unsigned long) n / (unsigned long) sizeof(DdNode));
+#else
+ (void) fprintf(dd->out,"T = 0x%x\t",(unsigned) n / (unsigned) sizeof(DdNode));
+#endif
+ T = 0;
+ }
+
+ n = cuddE(g);
+ N = Cudd_Regular(n);
+ if (cuddIsConstant(N)) {
+ (void) fprintf(dd->out,"E = %c%-9g\n",bang(n),cuddV(N));
+ E = 1;
+ } else {
+#if SIZEOF_VOID_P == 8
+ (void) fprintf(dd->out,"E = %c0x%lx\n", bang(n), (unsigned long) N/(unsigned long) sizeof(DdNode));
+#else
+ (void) fprintf(dd->out,"E = %c0x%x\n", bang(n), (unsigned) N/(unsigned) sizeof(DdNode));
+#endif
+ E = 0;
+ }
+ if (E == 0) {
+ if (dp2(dd,N,t) == 0)
+ return(0);
+ }
+ if (T == 0) {
+ if (dp2(dd,cuddT(g),t) == 0)
+ return(0);
+ }
+ return(1);
+
+} /* end of dp2 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_PrintMinterm.]
+
+ Description []
+
+ SideEffects [None]
+
+******************************************************************************/
+static void
+ddPrintMintermAux(
+ DdManager * dd /* manager */,
+ DdNode * node /* current node */,
+ int * list /* current recursion path */)
+{
+ DdNode *N,*Nv,*Nnv;
+ int i,v,index;
+
+ N = Cudd_Regular(node);
+
+ if (cuddIsConstant(N)) {
+ /* Terminal case: Print one cube based on the current recursion
+ ** path, unless we have reached the background value (ADDs) or
+ ** the logical zero (BDDs).
+ */
+ if (node != background && node != zero) {
+ for (i = 0; i < dd->size; i++) {
+ v = list[i];
+ if (v == 0) (void) fprintf(dd->out,"0");
+ else if (v == 1) (void) fprintf(dd->out,"1");
+ else (void) fprintf(dd->out,"-");
+ }
+ (void) fprintf(dd->out," % g\n", cuddV(node));
+ }
+ } else {
+ Nv = cuddT(N);
+ Nnv = cuddE(N);
+ if (Cudd_IsComplement(node)) {
+ Nv = Cudd_Not(Nv);
+ Nnv = Cudd_Not(Nnv);
+ }
+ index = N->index;
+ list[index] = 0;
+ ddPrintMintermAux(dd,Nnv,list);
+ list[index] = 1;
+ ddPrintMintermAux(dd,Nv,list);
+ list[index] = 2;
+ }
+ return;
+
+} /* end of ddPrintMintermAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_DagSize.]
+
+ Description [Performs the recursive step of Cudd_DagSize. Returns the
+ number of nodes in the graph rooted at n.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddDagInt(
+ DdNode * n)
+{
+ int tval, eval;
+
+ if (Cudd_IsComplement(n->next)) {
+ return(0);
+ }
+ n->next = Cudd_Not(n->next);
+ if (cuddIsConstant(n)) {
+ return(1);
+ }
+ tval = ddDagInt(cuddT(n));
+ eval = ddDagInt(Cudd_Regular(cuddE(n)));
+ return(1 + tval + eval);
+
+} /* end of ddDagInt */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_CofactorEstimate.]
+
+ Description [Performs the recursive step of Cudd_CofactorEstimate.
+ Returns an estimate of the number of nodes in the DD of a
+ cofactor of node. Uses the least significant bit of the next field as
+ visited flag. node is supposed to be regular; the invariant is maintained
+ by this procedure.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddEstimateCofactor(
+ DdManager *dd,
+ st_table *table,
+ DdNode * node,
+ int i,
+ int phase,
+ DdNode ** ptr)
+{
+ int tval, eval, val;
+ DdNode *ptrT, *ptrE;
+
+ if (Cudd_IsComplement(node->next)) {
+ if (!st_lookup(table,(char *)node,(char **)ptr)) {
+ st_add_direct(table,(char *)node,(char *)node);
+ *ptr = node;
+ }
+ return(0);
+ }
+ node->next = Cudd_Not(node->next);
+ if (cuddIsConstant(node)) {
+ *ptr = node;
+ if (st_add_direct(table,(char *)node,(char *)node) == ST_OUT_OF_MEM)
+ return(CUDD_OUT_OF_MEM);
+ return(1);
+ }
+ if ((int) node->index == i) {
+ if (phase == 1) {
+ *ptr = cuddT(node);
+ val = ddDagInt(cuddT(node));
+ } else {
+ *ptr = cuddE(node);
+ val = ddDagInt(Cudd_Regular(cuddE(node)));
+ }
+ if (node->ref > 1) {
+ if (st_add_direct(table,(char *)node,(char *)*ptr) ==
+ ST_OUT_OF_MEM)
+ return(CUDD_OUT_OF_MEM);
+ }
+ return(val);
+ }
+ if (dd->perm[node->index] > dd->perm[i]) {
+ *ptr = node;
+ tval = ddDagInt(cuddT(node));
+ eval = ddDagInt(Cudd_Regular(cuddE(node)));
+ if (node->ref > 1) {
+ if (st_add_direct(table,(char *)node,(char *)node) ==
+ ST_OUT_OF_MEM)
+ return(CUDD_OUT_OF_MEM);
+ }
+ val = 1 + tval + eval;
+ return(val);
+ }
+ tval = cuddEstimateCofactor(dd,table,cuddT(node),i,phase,&ptrT);
+ eval = cuddEstimateCofactor(dd,table,Cudd_Regular(cuddE(node)),i,
+ phase,&ptrE);
+ ptrE = Cudd_NotCond(ptrE,Cudd_IsComplement(cuddE(node)));
+ if (ptrT == ptrE) { /* recombination */
+ *ptr = ptrT;
+ val = tval;
+ if (node->ref > 1) {
+ if (st_add_direct(table,(char *)node,(char *)*ptr) ==
+ ST_OUT_OF_MEM)
+ return(CUDD_OUT_OF_MEM);
+ }
+ } else if ((ptrT != cuddT(node) || ptrE != cuddE(node)) &&
+ (*ptr = cuddUniqueLookup(dd,node->index,ptrT,ptrE)) != NULL) {
+ if (Cudd_IsComplement((*ptr)->next)) {
+ val = 0;
+ } else {
+ val = 1 + tval + eval;
+ }
+ if (node->ref > 1) {
+ if (st_add_direct(table,(char *)node,(char *)*ptr) ==
+ ST_OUT_OF_MEM)
+ return(CUDD_OUT_OF_MEM);
+ }
+ } else {
+ *ptr = node;
+ val = 1 + tval + eval;
+ }
+ return(val);
+
+} /* end of cuddEstimateCofactor */
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks the unique table for the existence of an internal node.]
+
+ Description [Checks the unique table for the existence of an internal
+ node. Returns a pointer to the node if it is in the table; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddUniqueInter]
+
+******************************************************************************/
+static DdNode *
+cuddUniqueLookup(
+ DdManager * unique,
+ int index,
+ DdNode * T,
+ DdNode * E)
+{
+ int posn;
+ unsigned int level;
+ DdNodePtr *nodelist;
+ DdNode *looking;
+ DdSubtable *subtable;
+
+ if (index >= unique->size) {
+ return(NULL);
+ }
+
+ level = unique->perm[index];
+ subtable = &(unique->subtables[level]);
+
+#ifdef DD_DEBUG
+ assert(level < (unsigned) cuddI(unique,T->index));
+ assert(level < (unsigned) cuddI(unique,Cudd_Regular(E)->index));
+#endif
+
+ posn = ddHash(T, E, subtable->shift);
+ nodelist = subtable->nodelist;
+ looking = nodelist[posn];
+
+ while (T < cuddT(looking)) {
+ looking = Cudd_Regular(looking->next);
+ }
+ while (T == cuddT(looking) && E < cuddE(looking)) {
+ looking = Cudd_Regular(looking->next);
+ }
+ if (cuddT(looking) == T && cuddE(looking) == E) {
+ return(looking);
+ }
+
+ return(NULL);
+
+} /* end of cuddUniqueLookup */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_CofactorEstimateSimple.]
+
+ Description [Performs the recursive step of Cudd_CofactorEstimateSimple.
+ Returns an estimate of the number of nodes in the DD of the positive
+ cofactor of node. Uses the least significant bit of the next field as
+ visited flag. node is supposed to be regular; the invariant is maintained
+ by this procedure.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddEstimateCofactorSimple(
+ DdNode * node,
+ int i)
+{
+ int tval, eval;
+
+ if (Cudd_IsComplement(node->next)) {
+ return(0);
+ }
+ node->next = Cudd_Not(node->next);
+ if (cuddIsConstant(node)) {
+ return(1);
+ }
+ tval = cuddEstimateCofactorSimple(cuddT(node),i);
+ if ((int) node->index == i) return(tval);
+ eval = cuddEstimateCofactorSimple(Cudd_Regular(cuddE(node)),i);
+ return(1 + tval + eval);
+
+} /* end of cuddEstimateCofactorSimple */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_CountMinterm.]
+
+ Description [Performs the recursive step of Cudd_CountMinterm.
+ It is based on the following identity. Let |f| be the
+ number of minterms of f. Then:
+ <xmp>
+ |f| = (|f0|+|f1|)/2
+ </xmp>
+ where f0 and f1 are the two cofactors of f. Does not use the
+ identity |f'| = max - |f|, to minimize loss of accuracy due to
+ roundoff. Returns the number of minterms of the function rooted at
+ node.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static double
+ddCountMintermAux(
+ DdNode * node,
+ double max,
+ DdHashTable * table)
+{
+ DdNode *N, *Nt, *Ne;
+ double min, minT, minE;
+ DdNode *res;
+
+ N = Cudd_Regular(node);
+
+ if (cuddIsConstant(N)) {
+ if (node == background || node == zero) {
+ return(0.0);
+ } else {
+ return(max);
+ }
+ }
+ if (N->ref != 1 && (res = cuddHashTableLookup1(table,node)) != NULL) {
+ min = cuddV(res);
+ if (res->ref == 0) {
+ table->manager->dead++;
+ table->manager->constants.dead++;
+ }
+ return(min);
+ }
+
+ Nt = cuddT(N); Ne = cuddE(N);
+ if (Cudd_IsComplement(node)) {
+ Nt = Cudd_Not(Nt); Ne = Cudd_Not(Ne);
+ }
+
+ minT = ddCountMintermAux(Nt,max,table);
+ if (minT == (double)CUDD_OUT_OF_MEM) return((double)CUDD_OUT_OF_MEM);
+ minT *= 0.5;
+ minE = ddCountMintermAux(Ne,max,table);
+ if (minE == (double)CUDD_OUT_OF_MEM) return((double)CUDD_OUT_OF_MEM);
+ minE *= 0.5;
+ min = minT + minE;
+
+ if (N->ref != 1) {
+ ptrint fanout = (ptrint) N->ref;
+ cuddSatDec(fanout);
+ res = cuddUniqueConst(table->manager,min);
+ if (!cuddHashTableInsert1(table,node,res,fanout)) {
+ cuddRef(res); Cudd_RecursiveDeref(table->manager, res);
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ }
+
+ return(min);
+
+} /* end of ddCountMintermAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_CountPath.]
+
+ Description [Performs the recursive step of Cudd_CountPath.
+ It is based on the following identity. Let |f| be the
+ number of paths of f. Then:
+ <xmp>
+ |f| = |f0|+|f1|
+ </xmp>
+ where f0 and f1 are the two cofactors of f. Uses the
+ identity |f'| = |f|, to improve the utilization of the (local) cache.
+ Returns the number of paths of the function rooted at node.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static double
+ddCountPathAux(
+ DdNode * node,
+ st_table * table)
+{
+
+ DdNode *Nv, *Nnv;
+ double paths, *ppaths, paths1, paths2;
+ double *dummy;
+
+
+ if (cuddIsConstant(node)) {
+ return(1.0);
+ }
+ if (st_lookup(table, (char *)node, (char **)&dummy)) {
+ paths = *dummy;
+ return(paths);
+ }
+
+ Nv = cuddT(node); Nnv = cuddE(node);
+
+ paths1 = ddCountPathAux(Nv,table);
+ if (paths1 == (double)CUDD_OUT_OF_MEM) return((double)CUDD_OUT_OF_MEM);
+ paths2 = ddCountPathAux(Cudd_Regular(Nnv),table);
+ if (paths2 == (double)CUDD_OUT_OF_MEM) return((double)CUDD_OUT_OF_MEM);
+ paths = paths1 + paths2;
+
+ ppaths = ALLOC(double,1);
+ if (ppaths == NULL) {
+ return((double)CUDD_OUT_OF_MEM);
+ }
+
+ *ppaths = paths;
+
+ if (st_add_direct(table,(char *)node, (char *)ppaths) == ST_OUT_OF_MEM) {
+ FREE(ppaths);
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ return(paths);
+
+} /* end of ddCountPathAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_CountMinterm.]
+
+ Description [Performs the recursive step of Cudd_CountMinterm.
+ It is based on the following identity. Let |f| be the
+ number of minterms of f. Then:
+ <xmp>
+ |f| = (|f0|+|f1|)/2
+ </xmp>
+ where f0 and f1 are the two cofactors of f. Does not use the
+ identity |f'| = max - |f|, to minimize loss of accuracy due to
+ roundoff. Returns the number of minterms of the function rooted at
+ node.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddEpdCountMintermAux(
+ DdNode * node,
+ EpDouble * max,
+ EpDouble * epd,
+ st_table * table)
+{
+ DdNode *Nt, *Ne;
+ EpDouble *min, minT, minE;
+ EpDouble *res;
+ int status;
+
+ if (cuddIsConstant(node)) {
+ if (node == background || node == zero) {
+ EpdMakeZero(epd, 0);
+ } else {
+ EpdCopy(max, epd);
+ }
+ return(0);
+ }
+ if (node->ref != 1 && st_lookup(table, (char *)node, (char **)&res)) {
+ EpdCopy(res, epd);
+ return(0);
+ }
+
+ Nt = cuddT(node); Ne = cuddE(node);
+ if (Cudd_IsComplement(node)) {
+ Nt = Cudd_Not(Nt); Ne = Cudd_Not(Ne);
+ }
+
+ status = ddEpdCountMintermAux(Nt,max,&minT,table);
+ if (status == CUDD_OUT_OF_MEM) return(CUDD_OUT_OF_MEM);
+ EpdMultiply(&minT, (double)0.5);
+ status = ddEpdCountMintermAux(Ne,max,&minE,table);
+ if (status == CUDD_OUT_OF_MEM) return(CUDD_OUT_OF_MEM);
+ if (Cudd_IsComplement(Ne)) {
+ EpdSubtract3(max, &minE, epd);
+ EpdCopy(epd, &minE);
+ }
+ EpdMultiply(&minE, (double)0.5);
+ EpdAdd3(&minT, &minE, epd);
+
+ if (node->ref > 1) {
+ min = EpdAlloc();
+ if (!min)
+ return(CUDD_OUT_OF_MEM);
+ EpdCopy(epd, min);
+ if (st_insert(table, (char *)node, (char *)min) == ST_OUT_OF_MEM) {
+ EpdFree(min);
+ return(CUDD_OUT_OF_MEM);
+ }
+ }
+
+ return(0);
+
+} /* end of ddEpdCountMintermAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_CountPathsToNonZero.]
+
+ Description [Performs the recursive step of Cudd_CountPathsToNonZero.
+ It is based on the following identity. Let |f| be the
+ number of paths of f. Then:
+ <xmp>
+ |f| = |f0|+|f1|
+ </xmp>
+ where f0 and f1 are the two cofactors of f. Returns the number of
+ paths of the function rooted at node.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static double
+ddCountPathsToNonZero(
+ DdNode * N,
+ st_table * table)
+{
+
+ DdNode *node, *Nt, *Ne;
+ double paths, *ppaths, paths1, paths2;
+ double *dummy;
+
+ node = Cudd_Regular(N);
+ if (cuddIsConstant(node)) {
+ return((double) !(Cudd_IsComplement(N) || cuddV(node)==DD_ZERO_VAL));
+ }
+ if (st_lookup(table, (char *)N, (char **)&dummy)) {
+ paths = *dummy;
+ return(paths);
+ }
+
+ Nt = cuddT(node); Ne = cuddE(node);
+ if (node != N) {
+ Nt = Cudd_Not(Nt); Ne = Cudd_Not(Ne);
+ }
+
+ paths1 = ddCountPathsToNonZero(Nt,table);
+ if (paths1 == (double)CUDD_OUT_OF_MEM) return((double)CUDD_OUT_OF_MEM);
+ paths2 = ddCountPathsToNonZero(Ne,table);
+ if (paths2 == (double)CUDD_OUT_OF_MEM) return((double)CUDD_OUT_OF_MEM);
+ paths = paths1 + paths2;
+
+ ppaths = ALLOC(double,1);
+ if (ppaths == NULL) {
+ return((double)CUDD_OUT_OF_MEM);
+ }
+
+ *ppaths = paths;
+
+ if (st_add_direct(table,(char *)N, (char *)ppaths) == ST_OUT_OF_MEM) {
+ FREE(ppaths);
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ return(paths);
+
+} /* end of ddCountPathsToNonZero */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_Support.]
+
+ Description [Performs the recursive step of Cudd_Support. Performs a
+ DFS from f. The support is accumulated in supp as a side effect. Uses
+ the LSB of the then pointer as visited flag.]
+
+ SideEffects [None]
+
+ SeeAlso [ddClearFlag]
+
+******************************************************************************/
+static void
+ddSupportStep(
+ DdNode * f,
+ int * support)
+{
+ if (cuddIsConstant(f) || Cudd_IsComplement(f->next)) {
+ return;
+ }
+
+ support[f->index] = 1;
+ ddSupportStep(cuddT(f),support);
+ ddSupportStep(Cudd_Regular(cuddE(f)),support);
+ /* Mark as visited. */
+ f->next = Cudd_Not(f->next);
+ return;
+
+} /* end of ddSupportStep */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs a DFS from f, clearing the LSB of the next
+ pointers.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [ddSupportStep ddDagInt]
+
+******************************************************************************/
+static void
+ddClearFlag(
+ DdNode * f)
+{
+ if (!Cudd_IsComplement(f->next)) {
+ return;
+ }
+ /* Clear visited flag. */
+ f->next = Cudd_Regular(f->next);
+ if (cuddIsConstant(f)) {
+ return;
+ }
+ ddClearFlag(cuddT(f));
+ ddClearFlag(Cudd_Regular(cuddE(f)));
+ return;
+
+} /* end of ddClearFlag */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_CountLeaves.]
+
+ Description [Performs the recursive step of Cudd_CountLeaves. Returns
+ the number of leaves in the DD rooted at n.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_CountLeaves]
+
+******************************************************************************/
+static int
+ddLeavesInt(
+ DdNode * n)
+{
+ int tval, eval;
+
+ if (Cudd_IsComplement(n->next)) {
+ return(0);
+ }
+ n->next = Cudd_Not(n->next);
+ if (cuddIsConstant(n)) {
+ return(1);
+ }
+ tval = ddLeavesInt(cuddT(n));
+ eval = ddLeavesInt(Cudd_Regular(cuddE(n)));
+ return(tval + eval);
+
+} /* end of ddLeavesInt */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddPickArbitraryMinterms.]
+
+ Description [Performs the recursive step of Cudd_bddPickArbitraryMinterms.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [none]
+
+ SeeAlso [Cudd_bddPickArbitraryMinterms]
+
+******************************************************************************/
+static int
+ddPickArbitraryMinterms(
+ DdManager *dd,
+ DdNode *node,
+ int nvars,
+ int nminterms,
+ char **string)
+{
+ DdNode *N, *T, *E;
+ DdNode *one, *bzero;
+ int i, t, result;
+ double min1, min2;
+
+ if (string == NULL || node == NULL) return(0);
+
+ /* The constant 0 function has no on-set cubes. */
+ one = DD_ONE(dd);
+ bzero = Cudd_Not(one);
+ if (nminterms == 0 || node == bzero) return(1);
+ if (node == one) {
+ return(1);
+ }
+
+ N = Cudd_Regular(node);
+ T = cuddT(N); E = cuddE(N);
+ if (Cudd_IsComplement(node)) {
+ T = Cudd_Not(T); E = Cudd_Not(E);
+ }
+
+ min1 = Cudd_CountMinterm(dd, T, nvars) / 2.0;
+ if (min1 == (double)CUDD_OUT_OF_MEM) return(0);
+ min2 = Cudd_CountMinterm(dd, E, nvars) / 2.0;
+ if (min2 == (double)CUDD_OUT_OF_MEM) return(0);
+
+ t = (int)((double)nminterms * min1 / (min1 + min2) + 0.5);
+ for (i = 0; i < t; i++)
+ string[i][N->index] = '1';
+ for (i = t; i < nminterms; i++)
+ string[i][N->index] = '0';
+
+ result = ddPickArbitraryMinterms(dd,T,nvars,t,&string[0]);
+ if (result == 0)
+ return(0);
+ result = ddPickArbitraryMinterms(dd,E,nvars,nminterms-t,&string[t]);
+ return(result);
+
+} /* end of ddPickArbitraryMinterms */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds a representative cube of a BDD.]
+
+ Description [Finds a representative cube of a BDD with the weight of
+ each variable. From the top variable, if the weight is greater than or
+ equal to 0.0, choose THEN branch unless the child is the constant 0.
+ Otherwise, choose ELSE branch unless the child is the constant 0.]
+
+ SideEffects [Cudd_SubsetWithMaskVars Cudd_bddPickOneCube]
+
+******************************************************************************/
+static int
+ddPickRepresentativeCube(
+ DdManager *dd,
+ DdNode *node,
+ int nvars,
+ double *weight,
+ char *string)
+{
+ DdNode *N, *T, *E;
+ DdNode *one, *bzero;
+
+ if (string == NULL || node == NULL) return(0);
+
+ /* The constant 0 function has no on-set cubes. */
+ one = DD_ONE(dd);
+ bzero = Cudd_Not(one);
+ if (node == bzero) return(0);
+
+ if (node == DD_ONE(dd)) return(1);
+
+ for (;;) {
+ N = Cudd_Regular(node);
+ if (N == one)
+ break;
+ T = cuddT(N);
+ E = cuddE(N);
+ if (Cudd_IsComplement(node)) {
+ T = Cudd_Not(T);
+ E = Cudd_Not(E);
+ }
+ if (weight[N->index] >= 0.0) {
+ if (T == bzero) {
+ node = E;
+ string[N->index] = '0';
+ } else {
+ node = T;
+ string[N->index] = '1';
+ }
+ } else {
+ if (E == bzero) {
+ node = T;
+ string[N->index] = '1';
+ } else {
+ node = E;
+ string[N->index] = '0';
+ }
+ }
+ }
+ return(1);
+
+} /* end of ddPickRepresentativeCube */
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees the memory used to store the minterm counts recorded
+ in the visited table.]
+
+ Description [Frees the memory used to store the minterm counts
+ recorded in the visited table. Returns ST_CONTINUE.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static enum st_retval
+ddEpdFree(
+ char * key,
+ char * value,
+ char * arg)
+{
+ EpDouble *epd;
+
+ epd = (EpDouble *) value;
+ EpdFree(epd);
+ return(ST_CONTINUE);
+
+} /* end of ddEpdFree */
diff --git a/src/bdd/cudd/cuddWindow.c b/src/bdd/cudd/cuddWindow.c
new file mode 100644
index 00000000..3e6d5686
--- /dev/null
+++ b/src/bdd/cudd/cuddWindow.c
@@ -0,0 +1,997 @@
+/**CFile***********************************************************************
+
+ FileName [cuddWindow.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions for window permutation]
+
+ Description [Internal procedures included in this module:
+ <ul>
+ <li> cuddWindowReorder()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> ddWindow2()
+ <li> ddWindowConv2()
+ <li> ddPermuteWindow3()
+ <li> ddWindow3()
+ <li> ddWindowConv3()
+ <li> ddPermuteWindow4()
+ <li> ddWindow4()
+ <li> ddWindowConv4()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddWindow.c,v 1.1.1.1 2003/02/24 22:23:53 wjiang Exp $";
+#endif
+
+#ifdef DD_STATS
+extern int ddTotalNumberSwapping;
+extern int ddTotalNISwaps;
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int ddWindow2 ARGS((DdManager *table, int low, int high));
+static int ddWindowConv2 ARGS((DdManager *table, int low, int high));
+static int ddPermuteWindow3 ARGS((DdManager *table, int x));
+static int ddWindow3 ARGS((DdManager *table, int low, int high));
+static int ddWindowConv3 ARGS((DdManager *table, int low, int high));
+static int ddPermuteWindow4 ARGS((DdManager *table, int w));
+static int ddWindow4 ARGS((DdManager *table, int low, int high));
+static int ddWindowConv4 ARGS((DdManager *table, int low, int high));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders by applying the method of the sliding window.]
+
+ Description [Reorders by applying the method of the sliding window.
+ Tries all possible permutations to the variables in a window that
+ slides from low to high. The size of the window is determined by
+ submethod. Assumes that no dead nodes are present. Returns 1 in
+ case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+int
+cuddWindowReorder(
+ DdManager * table /* DD table */,
+ int low /* lowest index to reorder */,
+ int high /* highest index to reorder */,
+ Cudd_ReorderingType submethod /* window reordering option */)
+{
+
+ int res;
+#ifdef DD_DEBUG
+ int supposedOpt;
+#endif
+
+ switch (submethod) {
+ case CUDD_REORDER_WINDOW2:
+ res = ddWindow2(table,low,high);
+ break;
+ case CUDD_REORDER_WINDOW3:
+ res = ddWindow3(table,low,high);
+ break;
+ case CUDD_REORDER_WINDOW4:
+ res = ddWindow4(table,low,high);
+ break;
+ case CUDD_REORDER_WINDOW2_CONV:
+ res = ddWindowConv2(table,low,high);
+ break;
+ case CUDD_REORDER_WINDOW3_CONV:
+ res = ddWindowConv3(table,low,high);
+#ifdef DD_DEBUG
+ supposedOpt = table->keys - table->isolated;
+ res = ddWindow3(table,low,high);
+ if (table->keys - table->isolated != (unsigned) supposedOpt) {
+ (void) fprintf(table->err, "Convergence failed! (%d != %d)\n",
+ table->keys - table->isolated, supposedOpt);
+ }
+#endif
+ break;
+ case CUDD_REORDER_WINDOW4_CONV:
+ res = ddWindowConv4(table,low,high);
+#ifdef DD_DEBUG
+ supposedOpt = table->keys - table->isolated;
+ res = ddWindow4(table,low,high);
+ if (table->keys - table->isolated != (unsigned) supposedOpt) {
+ (void) fprintf(table->err,"Convergence failed! (%d != %d)\n",
+ table->keys - table->isolated, supposedOpt);
+ }
+#endif
+ break;
+ default: return(0);
+ }
+
+ return(res);
+
+} /* end of cuddWindowReorder */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Reorders by applying a sliding window of width 2.]
+
+ Description [Reorders by applying a sliding window of width 2.
+ Tries both permutations of the variables in a window
+ that slides from low to high. Assumes that no dead nodes are
+ present. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddWindow2(
+ DdManager * table,
+ int low,
+ int high)
+{
+
+ int x;
+ int res;
+ int size;
+
+#ifdef DD_DEBUG
+ assert(low >= 0 && high < table->size);
+#endif
+
+ if (high-low < 1) return(0);
+
+ res = table->keys - table->isolated;
+ for (x = low; x < high; x++) {
+ size = res;
+ res = cuddSwapInPlace(table,x,x+1);
+ if (res == 0) return(0);
+ if (res >= size) { /* no improvement: undo permutation */
+ res = cuddSwapInPlace(table,x,x+1);
+ if (res == 0) return(0);
+ }
+#ifdef DD_STATS
+ if (res < size) {
+ (void) fprintf(table->out,"-");
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+
+ return(1);
+
+} /* end of ddWindow2 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders by repeatedly applying a sliding window of width 2.]
+
+ Description [Reorders by repeatedly applying a sliding window of width
+ 2. Tries both permutations of the variables in a window
+ that slides from low to high. Assumes that no dead nodes are
+ present. Uses an event-driven approach to determine convergence.
+ Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddWindowConv2(
+ DdManager * table,
+ int low,
+ int high)
+{
+ int x;
+ int res;
+ int nwin;
+ int newevent;
+ int *events;
+ int size;
+
+#ifdef DD_DEBUG
+ assert(low >= 0 && high < table->size);
+#endif
+
+ if (high-low < 1) return(ddWindowConv2(table,low,high));
+
+ nwin = high-low;
+ events = ALLOC(int,nwin);
+ if (events == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (x=0; x<nwin; x++) {
+ events[x] = 1;
+ }
+
+ res = table->keys - table->isolated;
+ do {
+ newevent = 0;
+ for (x=0; x<nwin; x++) {
+ if (events[x]) {
+ size = res;
+ res = cuddSwapInPlace(table,x+low,x+low+1);
+ if (res == 0) {
+ FREE(events);
+ return(0);
+ }
+ if (res >= size) { /* no improvement: undo permutation */
+ res = cuddSwapInPlace(table,x+low,x+low+1);
+ if (res == 0) {
+ FREE(events);
+ return(0);
+ }
+ }
+ if (res < size) {
+ if (x < nwin-1) events[x+1] = 1;
+ if (x > 0) events[x-1] = 1;
+ newevent = 1;
+ }
+ events[x] = 0;
+#ifdef DD_STATS
+ if (res < size) {
+ (void) fprintf(table->out,"-");
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+ }
+#ifdef DD_STATS
+ if (newevent) {
+ (void) fprintf(table->out,"|");
+ fflush(table->out);
+ }
+#endif
+ } while (newevent);
+
+ FREE(events);
+
+ return(1);
+
+} /* end of ddWindowConv3 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Tries all the permutations of the three variables between
+ x and x+2 and retains the best.]
+
+ Description [Tries all the permutations of the three variables between
+ x and x+2 and retains the best. Assumes that no dead nodes are
+ present. Returns the index of the best permutation (1-6) in case of
+ success; 0 otherwise.Assumes that no dead nodes are present. Returns
+ the index of the best permutation (1-6) in case of success; 0
+ otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddPermuteWindow3(
+ DdManager * table,
+ int x)
+{
+ int y,z;
+ int size,sizeNew;
+ int best;
+
+#ifdef DD_DEBUG
+ assert(table->dead == 0);
+ assert(x+2 < table->size);
+#endif
+
+ size = table->keys - table->isolated;
+ y = x+1; z = y+1;
+
+ /* The permutation pattern is:
+ ** (x,y)(y,z)
+ ** repeated three times to get all 3! = 6 permutations.
+ */
+#define ABC 1
+ best = ABC;
+
+#define BAC 2
+ sizeNew = cuddSwapInPlace(table,x,y);
+ if (sizeNew < size) {
+ if (sizeNew == 0) return(0);
+ best = BAC;
+ size = sizeNew;
+ }
+#define BCA 3
+ sizeNew = cuddSwapInPlace(table,y,z);
+ if (sizeNew < size) {
+ if (sizeNew == 0) return(0);
+ best = BCA;
+ size = sizeNew;
+ }
+#define CBA 4
+ sizeNew = cuddSwapInPlace(table,x,y);
+ if (sizeNew < size) {
+ if (sizeNew == 0) return(0);
+ best = CBA;
+ size = sizeNew;
+ }
+#define CAB 5
+ sizeNew = cuddSwapInPlace(table,y,z);
+ if (sizeNew < size) {
+ if (sizeNew == 0) return(0);
+ best = CAB;
+ size = sizeNew;
+ }
+#define ACB 6
+ sizeNew = cuddSwapInPlace(table,x,y);
+ if (sizeNew < size) {
+ if (sizeNew == 0) return(0);
+ best = ACB;
+ size = sizeNew;
+ }
+
+ /* Now take the shortest route to the best permuytation.
+ ** The initial permutation is ACB.
+ */
+ switch(best) {
+ case BCA: if (!cuddSwapInPlace(table,y,z)) return(0);
+ case CBA: if (!cuddSwapInPlace(table,x,y)) return(0);
+ case ABC: if (!cuddSwapInPlace(table,y,z)) return(0);
+ case ACB: break;
+ case BAC: if (!cuddSwapInPlace(table,y,z)) return(0);
+ case CAB: if (!cuddSwapInPlace(table,x,y)) return(0);
+ break;
+ default: return(0);
+ }
+
+#ifdef DD_DEBUG
+ assert(table->keys - table->isolated == (unsigned) size);
+#endif
+
+ return(best);
+
+} /* end of ddPermuteWindow3 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders by applying a sliding window of width 3.]
+
+ Description [Reorders by applying a sliding window of width 3.
+ Tries all possible permutations to the variables in a
+ window that slides from low to high. Assumes that no dead nodes are
+ present. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddWindow3(
+ DdManager * table,
+ int low,
+ int high)
+{
+
+ int x;
+ int res;
+
+#ifdef DD_DEBUG
+ assert(low >= 0 && high < table->size);
+#endif
+
+ if (high-low < 2) return(ddWindow2(table,low,high));
+
+ for (x = low; x+1 < high; x++) {
+ res = ddPermuteWindow3(table,x);
+ if (res == 0) return(0);
+#ifdef DD_STATS
+ if (res == ABC) {
+ (void) fprintf(table->out,"=");
+ } else {
+ (void) fprintf(table->out,"-");
+ }
+ fflush(table->out);
+#endif
+ }
+
+ return(1);
+
+} /* end of ddWindow3 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders by repeatedly applying a sliding window of width 3.]
+
+ Description [Reorders by repeatedly applying a sliding window of width
+ 3. Tries all possible permutations to the variables in a
+ window that slides from low to high. Assumes that no dead nodes are
+ present. Uses an event-driven approach to determine convergence.
+ Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddWindowConv3(
+ DdManager * table,
+ int low,
+ int high)
+{
+ int x;
+ int res;
+ int nwin;
+ int newevent;
+ int *events;
+
+#ifdef DD_DEBUG
+ assert(low >= 0 && high < table->size);
+#endif
+
+ if (high-low < 2) return(ddWindowConv2(table,low,high));
+
+ nwin = high-low-1;
+ events = ALLOC(int,nwin);
+ if (events == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (x=0; x<nwin; x++) {
+ events[x] = 1;
+ }
+
+ do {
+ newevent = 0;
+ for (x=0; x<nwin; x++) {
+ if (events[x]) {
+ res = ddPermuteWindow3(table,x+low);
+ switch (res) {
+ case ABC:
+ break;
+ case BAC:
+ if (x < nwin-1) events[x+1] = 1;
+ if (x > 1) events[x-2] = 1;
+ newevent = 1;
+ break;
+ case BCA:
+ case CBA:
+ case CAB:
+ if (x < nwin-2) events[x+2] = 1;
+ if (x < nwin-1) events[x+1] = 1;
+ if (x > 0) events[x-1] = 1;
+ if (x > 1) events[x-2] = 1;
+ newevent = 1;
+ break;
+ case ACB:
+ if (x < nwin-2) events[x+2] = 1;
+ if (x > 0) events[x-1] = 1;
+ newevent = 1;
+ break;
+ default:
+ FREE(events);
+ return(0);
+ }
+ events[x] = 0;
+#ifdef DD_STATS
+ if (res == ABC) {
+ (void) fprintf(table->out,"=");
+ } else {
+ (void) fprintf(table->out,"-");
+ }
+ fflush(table->out);
+#endif
+ }
+ }
+#ifdef DD_STATS
+ if (newevent) {
+ (void) fprintf(table->out,"|");
+ fflush(table->out);
+ }
+#endif
+ } while (newevent);
+
+ FREE(events);
+
+ return(1);
+
+} /* end of ddWindowConv3 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Tries all the permutations of the four variables between w
+ and w+3 and retains the best.]
+
+ Description [Tries all the permutations of the four variables between
+ w and w+3 and retains the best. Assumes that no dead nodes are
+ present. Returns the index of the best permutation (1-24) in case of
+ success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddPermuteWindow4(
+ DdManager * table,
+ int w)
+{
+ int x,y,z;
+ int size,sizeNew;
+ int best;
+
+#ifdef DD_DEBUG
+ assert(table->dead == 0);
+ assert(w+3 < table->size);
+#endif
+
+ size = table->keys - table->isolated;
+ x = w+1; y = x+1; z = y+1;
+
+ /* The permutation pattern is:
+ * (w,x)(y,z)(w,x)(x,y)
+ * (y,z)(w,x)(y,z)(x,y)
+ * repeated three times to get all 4! = 24 permutations.
+ * This gives a hamiltonian circuit of Cayley's graph.
+ * The codes to the permutation are assigned in topological order.
+ * The permutations at lower distance from the final permutation are
+ * assigned lower codes. This way we can choose, between
+ * permutations that give the same size, one that requires the minimum
+ * number of swaps from the final permutation of the hamiltonian circuit.
+ * There is an exception to this rule: ABCD is given Code 1, to
+ * avoid oscillation when convergence is sought.
+ */
+#define ABCD 1
+ best = ABCD;
+
+#define BACD 7
+ sizeNew = cuddSwapInPlace(table,w,x);
+ if (sizeNew < size) {
+ if (sizeNew == 0) return(0);
+ best = BACD;
+ size = sizeNew;
+ }
+#define BADC 13
+ sizeNew = cuddSwapInPlace(table,y,z);
+ if (sizeNew < size) {
+ if (sizeNew == 0) return(0);
+ best = BADC;
+ size = sizeNew;
+ }
+#define ABDC 8
+ sizeNew = cuddSwapInPlace(table,w,x);
+ if (sizeNew < size || (sizeNew == size && ABDC < best)) {
+ if (sizeNew == 0) return(0);
+ best = ABDC;
+ size = sizeNew;
+ }
+#define ADBC 14
+ sizeNew = cuddSwapInPlace(table,x,y);
+ if (sizeNew < size) {
+ if (sizeNew == 0) return(0);
+ best = ADBC;
+ size = sizeNew;
+ }
+#define ADCB 9
+ sizeNew = cuddSwapInPlace(table,y,z);
+ if (sizeNew < size || (sizeNew == size && ADCB < best)) {
+ if (sizeNew == 0) return(0);
+ best = ADCB;
+ size = sizeNew;
+ }
+#define DACB 15
+ sizeNew = cuddSwapInPlace(table,w,x);
+ if (sizeNew < size) {
+ if (sizeNew == 0) return(0);
+ best = DACB;
+ size = sizeNew;
+ }
+#define DABC 20
+ sizeNew = cuddSwapInPlace(table,y,z);
+ if (sizeNew < size) {
+ if (sizeNew == 0) return(0);
+ best = DABC;
+ size = sizeNew;
+ }
+#define DBAC 23
+ sizeNew = cuddSwapInPlace(table,x,y);
+ if (sizeNew < size) {
+ if (sizeNew == 0) return(0);
+ best = DBAC;
+ size = sizeNew;
+ }
+#define BDAC 19
+ sizeNew = cuddSwapInPlace(table,w,x);
+ if (sizeNew < size || (sizeNew == size && BDAC < best)) {
+ if (sizeNew == 0) return(0);
+ best = BDAC;
+ size = sizeNew;
+ }
+#define BDCA 21
+ sizeNew = cuddSwapInPlace(table,y,z);
+ if (sizeNew < size || (sizeNew == size && BDCA < best)) {
+ if (sizeNew == 0) return(0);
+ best = BDCA;
+ size = sizeNew;
+ }
+#define DBCA 24
+ sizeNew = cuddSwapInPlace(table,w,x);
+ if (sizeNew < size) {
+ if (sizeNew == 0) return(0);
+ best = DBCA;
+ size = sizeNew;
+ }
+#define DCBA 22
+ sizeNew = cuddSwapInPlace(table,x,y);
+ if (sizeNew < size || (sizeNew == size && DCBA < best)) {
+ if (sizeNew == 0) return(0);
+ best = DCBA;
+ size = sizeNew;
+ }
+#define DCAB 18
+ sizeNew = cuddSwapInPlace(table,y,z);
+ if (sizeNew < size || (sizeNew == size && DCAB < best)) {
+ if (sizeNew == 0) return(0);
+ best = DCAB;
+ size = sizeNew;
+ }
+#define CDAB 12
+ sizeNew = cuddSwapInPlace(table,w,x);
+ if (sizeNew < size || (sizeNew == size && CDAB < best)) {
+ if (sizeNew == 0) return(0);
+ best = CDAB;
+ size = sizeNew;
+ }
+#define CDBA 17
+ sizeNew = cuddSwapInPlace(table,y,z);
+ if (sizeNew < size || (sizeNew == size && CDBA < best)) {
+ if (sizeNew == 0) return(0);
+ best = CDBA;
+ size = sizeNew;
+ }
+#define CBDA 11
+ sizeNew = cuddSwapInPlace(table,x,y);
+ if (sizeNew < size || (sizeNew == size && CBDA < best)) {
+ if (sizeNew == 0) return(0);
+ best = CBDA;
+ size = sizeNew;
+ }
+#define BCDA 16
+ sizeNew = cuddSwapInPlace(table,w,x);
+ if (sizeNew < size || (sizeNew == size && BCDA < best)) {
+ if (sizeNew == 0) return(0);
+ best = BCDA;
+ size = sizeNew;
+ }
+#define BCAD 10
+ sizeNew = cuddSwapInPlace(table,y,z);
+ if (sizeNew < size || (sizeNew == size && BCAD < best)) {
+ if (sizeNew == 0) return(0);
+ best = BCAD;
+ size = sizeNew;
+ }
+#define CBAD 5
+ sizeNew = cuddSwapInPlace(table,w,x);
+ if (sizeNew < size || (sizeNew == size && CBAD < best)) {
+ if (sizeNew == 0) return(0);
+ best = CBAD;
+ size = sizeNew;
+ }
+#define CABD 3
+ sizeNew = cuddSwapInPlace(table,x,y);
+ if (sizeNew < size || (sizeNew == size && CABD < best)) {
+ if (sizeNew == 0) return(0);
+ best = CABD;
+ size = sizeNew;
+ }
+#define CADB 6
+ sizeNew = cuddSwapInPlace(table,y,z);
+ if (sizeNew < size || (sizeNew == size && CADB < best)) {
+ if (sizeNew == 0) return(0);
+ best = CADB;
+ size = sizeNew;
+ }
+#define ACDB 4
+ sizeNew = cuddSwapInPlace(table,w,x);
+ if (sizeNew < size || (sizeNew == size && ACDB < best)) {
+ if (sizeNew == 0) return(0);
+ best = ACDB;
+ size = sizeNew;
+ }
+#define ACBD 2
+ sizeNew = cuddSwapInPlace(table,y,z);
+ if (sizeNew < size || (sizeNew == size && ACBD < best)) {
+ if (sizeNew == 0) return(0);
+ best = ACBD;
+ size = sizeNew;
+ }
+
+ /* Now take the shortest route to the best permutation.
+ ** The initial permutation is ACBD.
+ */
+ switch(best) {
+ case DBCA: if (!cuddSwapInPlace(table,y,z)) return(0);
+ case BDCA: if (!cuddSwapInPlace(table,x,y)) return(0);
+ case CDBA: if (!cuddSwapInPlace(table,w,x)) return(0);
+ case ADBC: if (!cuddSwapInPlace(table,y,z)) return(0);
+ case ABDC: if (!cuddSwapInPlace(table,x,y)) return(0);
+ case ACDB: if (!cuddSwapInPlace(table,y,z)) return(0);
+ case ACBD: break;
+ case DCBA: if (!cuddSwapInPlace(table,y,z)) return(0);
+ case BCDA: if (!cuddSwapInPlace(table,x,y)) return(0);
+ case CBDA: if (!cuddSwapInPlace(table,w,x)) return(0);
+ if (!cuddSwapInPlace(table,x,y)) return(0);
+ if (!cuddSwapInPlace(table,y,z)) return(0);
+ break;
+ case DBAC: if (!cuddSwapInPlace(table,x,y)) return(0);
+ case DCAB: if (!cuddSwapInPlace(table,w,x)) return(0);
+ case DACB: if (!cuddSwapInPlace(table,y,z)) return(0);
+ case BACD: if (!cuddSwapInPlace(table,x,y)) return(0);
+ case CABD: if (!cuddSwapInPlace(table,w,x)) return(0);
+ break;
+ case DABC: if (!cuddSwapInPlace(table,y,z)) return(0);
+ case BADC: if (!cuddSwapInPlace(table,x,y)) return(0);
+ case CADB: if (!cuddSwapInPlace(table,w,x)) return(0);
+ if (!cuddSwapInPlace(table,y,z)) return(0);
+ break;
+ case BDAC: if (!cuddSwapInPlace(table,x,y)) return(0);
+ case CDAB: if (!cuddSwapInPlace(table,w,x)) return(0);
+ case ADCB: if (!cuddSwapInPlace(table,y,z)) return(0);
+ case ABCD: if (!cuddSwapInPlace(table,x,y)) return(0);
+ break;
+ case BCAD: if (!cuddSwapInPlace(table,x,y)) return(0);
+ case CBAD: if (!cuddSwapInPlace(table,w,x)) return(0);
+ if (!cuddSwapInPlace(table,x,y)) return(0);
+ break;
+ default: return(0);
+ }
+
+#ifdef DD_DEBUG
+ assert(table->keys - table->isolated == (unsigned) size);
+#endif
+
+ return(best);
+
+} /* end of ddPermuteWindow4 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders by applying a sliding window of width 4.]
+
+ Description [Reorders by applying a sliding window of width 4.
+ Tries all possible permutations to the variables in a
+ window that slides from low to high. Assumes that no dead nodes are
+ present. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddWindow4(
+ DdManager * table,
+ int low,
+ int high)
+{
+
+ int w;
+ int res;
+
+#ifdef DD_DEBUG
+ assert(low >= 0 && high < table->size);
+#endif
+
+ if (high-low < 3) return(ddWindow3(table,low,high));
+
+ for (w = low; w+2 < high; w++) {
+ res = ddPermuteWindow4(table,w);
+ if (res == 0) return(0);
+#ifdef DD_STATS
+ if (res == ABCD) {
+ (void) fprintf(table->out,"=");
+ } else {
+ (void) fprintf(table->out,"-");
+ }
+ fflush(table->out);
+#endif
+ }
+
+ return(1);
+
+} /* end of ddWindow4 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders by repeatedly applying a sliding window of width 4.]
+
+ Description [Reorders by repeatedly applying a sliding window of width
+ 4. Tries all possible permutations to the variables in a
+ window that slides from low to high. Assumes that no dead nodes are
+ present. Uses an event-driven approach to determine convergence.
+ Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+ddWindowConv4(
+ DdManager * table,
+ int low,
+ int high)
+{
+ int x;
+ int res;
+ int nwin;
+ int newevent;
+ int *events;
+
+#ifdef DD_DEBUG
+ assert(low >= 0 && high < table->size);
+#endif
+
+ if (high-low < 3) return(ddWindowConv3(table,low,high));
+
+ nwin = high-low-2;
+ events = ALLOC(int,nwin);
+ if (events == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (x=0; x<nwin; x++) {
+ events[x] = 1;
+ }
+
+ do {
+ newevent = 0;
+ for (x=0; x<nwin; x++) {
+ if (events[x]) {
+ res = ddPermuteWindow4(table,x+low);
+ switch (res) {
+ case ABCD:
+ break;
+ case BACD:
+ if (x < nwin-1) events[x+1] = 1;
+ if (x > 2) events[x-3] = 1;
+ newevent = 1;
+ break;
+ case BADC:
+ if (x < nwin-3) events[x+3] = 1;
+ if (x < nwin-1) events[x+1] = 1;
+ if (x > 0) events[x-1] = 1;
+ if (x > 2) events[x-3] = 1;
+ newevent = 1;
+ break;
+ case ABDC:
+ if (x < nwin-3) events[x+3] = 1;
+ if (x > 0) events[x-1] = 1;
+ newevent = 1;
+ break;
+ case ADBC:
+ case ADCB:
+ case ACDB:
+ if (x < nwin-3) events[x+3] = 1;
+ if (x < nwin-2) events[x+2] = 1;
+ if (x > 0) events[x-1] = 1;
+ if (x > 1) events[x-2] = 1;
+ newevent = 1;
+ break;
+ case DACB:
+ case DABC:
+ case DBAC:
+ case BDAC:
+ case BDCA:
+ case DBCA:
+ case DCBA:
+ case DCAB:
+ case CDAB:
+ case CDBA:
+ case CBDA:
+ case BCDA:
+ case CADB:
+ if (x < nwin-3) events[x+3] = 1;
+ if (x < nwin-2) events[x+2] = 1;
+ if (x < nwin-1) events[x+1] = 1;
+ if (x > 0) events[x-1] = 1;
+ if (x > 1) events[x-2] = 1;
+ if (x > 2) events[x-3] = 1;
+ newevent = 1;
+ break;
+ case BCAD:
+ case CBAD:
+ case CABD:
+ if (x < nwin-2) events[x+2] = 1;
+ if (x < nwin-1) events[x+1] = 1;
+ if (x > 1) events[x-2] = 1;
+ if (x > 2) events[x-3] = 1;
+ newevent = 1;
+ break;
+ case ACBD:
+ if (x < nwin-2) events[x+2] = 1;
+ if (x > 1) events[x-2] = 1;
+ newevent = 1;
+ break;
+ default:
+ FREE(events);
+ return(0);
+ }
+ events[x] = 0;
+#ifdef DD_STATS
+ if (res == ABCD) {
+ (void) fprintf(table->out,"=");
+ } else {
+ (void) fprintf(table->out,"-");
+ }
+ fflush(table->out);
+#endif
+ }
+ }
+#ifdef DD_STATS
+ if (newevent) {
+ (void) fprintf(table->out,"|");
+ fflush(table->out);
+ }
+#endif
+ } while (newevent);
+
+ FREE(events);
+
+ return(1);
+
+} /* end of ddWindowConv4 */
+
diff --git a/src/bdd/cudd/cuddZddCount.c b/src/bdd/cudd/cuddZddCount.c
new file mode 100644
index 00000000..29cf0c14
--- /dev/null
+++ b/src/bdd/cudd/cuddZddCount.c
@@ -0,0 +1,324 @@
+/**CFile***********************************************************************
+
+ FileName [cuddZddCount.c]
+
+ PackageName [cudd]
+
+ Synopsis [Procedures to count the number of minterms of a ZDD.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_zddCount();
+ <li> Cudd_zddCountDouble();
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> cuddZddCountStep();
+ <li> cuddZddCountDoubleStep();
+ <li> st_zdd_count_dbl_free()
+ <li> st_zdd_countfree()
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [Hyong-Kyoon Shin, In-Ho Moon]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddZddCount.c,v 1.1.1.1 2003/02/24 22:23:53 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int cuddZddCountStep ARGS((DdNode *P, st_table *table, DdNode *base, DdNode *empty));
+static double cuddZddCountDoubleStep ARGS((DdNode *P, st_table *table, DdNode *base, DdNode *empty));
+static enum st_retval st_zdd_countfree ARGS((char *key, char *value, char *arg));
+static enum st_retval st_zdd_count_dbl_free ARGS((char *key, char *value, char *arg));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the number of minterms in a ZDD.]
+
+ Description [Returns an integer representing the number of minterms
+ in a ZDD.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddCountDouble]
+
+******************************************************************************/
+int
+Cudd_zddCount(
+ DdManager * zdd,
+ DdNode * P)
+{
+ st_table *table;
+ int res;
+ DdNode *base, *empty;
+
+ base = DD_ONE(zdd);
+ empty = DD_ZERO(zdd);
+ table = st_init_table(st_ptrcmp, st_ptrhash);
+ if (table == NULL) return(CUDD_OUT_OF_MEM);
+ res = cuddZddCountStep(P, table, base, empty);
+ if (res == CUDD_OUT_OF_MEM) {
+ zdd->errorCode = CUDD_MEMORY_OUT;
+ }
+ st_foreach(table, st_zdd_countfree, NIL(char));
+ st_free_table(table);
+
+ return(res);
+
+} /* end of Cudd_zddCount */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the number of minterms of a ZDD.]
+
+ Description [Counts the number of minterms of a ZDD. The result is
+ returned as a double. If the procedure runs out of memory, it
+ returns (double) CUDD_OUT_OF_MEM. This procedure is used in
+ Cudd_zddCountMinterm.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddCountMinterm Cudd_zddCount]
+
+******************************************************************************/
+double
+Cudd_zddCountDouble(
+ DdManager * zdd,
+ DdNode * P)
+{
+ st_table *table;
+ double res;
+ DdNode *base, *empty;
+
+ base = DD_ONE(zdd);
+ empty = DD_ZERO(zdd);
+ table = st_init_table(st_ptrcmp, st_ptrhash);
+ if (table == NULL) return((double)CUDD_OUT_OF_MEM);
+ res = cuddZddCountDoubleStep(P, table, base, empty);
+ if (res == (double)CUDD_OUT_OF_MEM) {
+ zdd->errorCode = CUDD_MEMORY_OUT;
+ }
+ st_foreach(table, st_zdd_count_dbl_free, NIL(char));
+ st_free_table(table);
+
+ return(res);
+
+} /* end of Cudd_zddCountDouble */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddCount.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddZddCountStep(
+ DdNode * P,
+ st_table * table,
+ DdNode * base,
+ DdNode * empty)
+{
+ int res;
+ int *dummy;
+
+ if (P == empty)
+ return(0);
+ if (P == base)
+ return(1);
+
+ /* Check cache. */
+ if (st_lookup(table, (char *)P, (char **)(&dummy))) {
+ res = *dummy;
+ return(res);
+ }
+
+ res = cuddZddCountStep(cuddE(P), table, base, empty) +
+ cuddZddCountStep(cuddT(P), table, base, empty);
+
+ dummy = ALLOC(int, 1);
+ if (dummy == NULL) {
+ return(CUDD_OUT_OF_MEM);
+ }
+ *dummy = res;
+ if (st_insert(table, (char *)P, (char *)dummy) == ST_OUT_OF_MEM) {
+ FREE(dummy);
+ return(CUDD_OUT_OF_MEM);
+ }
+
+ return(res);
+
+} /* end of cuddZddCountStep */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddCountDouble.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static double
+cuddZddCountDoubleStep(
+ DdNode * P,
+ st_table * table,
+ DdNode * base,
+ DdNode * empty)
+{
+ double res;
+ double *dummy;
+
+ if (P == empty)
+ return((double)0.0);
+ if (P == base)
+ return((double)1.0);
+
+ /* Check cache */
+ if (st_lookup(table, (char *)P, (char **)(&dummy))) {
+ res = *dummy;
+ return(res);
+ }
+
+ res = cuddZddCountDoubleStep(cuddE(P), table, base, empty) +
+ cuddZddCountDoubleStep(cuddT(P), table, base, empty);
+
+ dummy = ALLOC(double, 1);
+ if (dummy == NULL) {
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ *dummy = res;
+ if (st_insert(table, (char *)P, (char *)dummy) == ST_OUT_OF_MEM) {
+ FREE(dummy);
+ return((double)CUDD_OUT_OF_MEM);
+ }
+
+ return(res);
+
+} /* end of cuddZddCountDoubleStep */
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees the memory associated with the computed table of
+ Cudd_zddCount.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static enum st_retval
+st_zdd_countfree(
+ char * key,
+ char * value,
+ char * arg)
+{
+ int *d;
+
+ d = (int *)value;
+ FREE(d);
+ return(ST_CONTINUE);
+
+} /* end of st_zdd_countfree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees the memory associated with the computed table of
+ Cudd_zddCountDouble.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static enum st_retval
+st_zdd_count_dbl_free(
+ char * key,
+ char * value,
+ char * arg)
+{
+ double *d;
+
+ d = (double *)value;
+ FREE(d);
+ return(ST_CONTINUE);
+
+} /* end of st_zdd_count_dbl_free */
diff --git a/src/bdd/cudd/cuddZddFuncs.c b/src/bdd/cudd/cuddZddFuncs.c
new file mode 100644
index 00000000..f938e1de
--- /dev/null
+++ b/src/bdd/cudd/cuddZddFuncs.c
@@ -0,0 +1,1603 @@
+/**CFile***********************************************************************
+
+ FileName [cuddZddFuncs.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions to manipulate covers represented as ZDDs.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_zddProduct();
+ <li> Cudd_zddUnateProduct();
+ <li> Cudd_zddWeakDiv();
+ <li> Cudd_zddWeakDivF();
+ <li> Cudd_zddDivide();
+ <li> Cudd_zddDivideF();
+ <li> Cudd_zddComplement();
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddZddProduct();
+ <li> cuddZddUnateProduct();
+ <li> cuddZddWeakDiv();
+ <li> cuddZddWeakDivF();
+ <li> cuddZddDivide();
+ <li> cuddZddDivideF();
+ <li> cuddZddGetCofactors3()
+ <li> cuddZddGetCofactors2()
+ <li> cuddZddComplement();
+ <li> cuddZddGetPosVarIndex();
+ <li> cuddZddGetNegVarIndex();
+ <li> cuddZddGetPosVarLevel();
+ <li> cuddZddGetNegVarLevel();
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [In-Ho Moon]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddZddFuncs.c,v 1.1.1.1 2003/02/24 22:23:53 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the product of two covers represented by ZDDs.]
+
+ Description [Computes the product of two covers represented by
+ ZDDs. The result is also a ZDD. Returns a pointer to the result if
+ successful; NULL otherwise. The covers on which Cudd_zddProduct
+ operates use two ZDD variables for each function variable (one ZDD
+ variable for each literal of the variable). Those two ZDD variables
+ should be adjacent in the order.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddUnateProduct]
+
+******************************************************************************/
+DdNode *
+Cudd_zddProduct(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddZddProduct(dd, f, g);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_zddProduct */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the product of two unate covers.]
+
+ Description [Computes the product of two unate covers represented as
+ ZDDs. Unate covers use one ZDD variable for each BDD
+ variable. Returns a pointer to the result if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddProduct]
+
+******************************************************************************/
+DdNode *
+Cudd_zddUnateProduct(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddZddUnateProduct(dd, f, g);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_zddUnateProduct */
+
+
+/**Function********************************************************************
+
+ Synopsis [Applies weak division to two covers.]
+
+ Description [Applies weak division to two ZDDs representing two
+ covers. Returns a pointer to the ZDD representing the result if
+ successful; NULL otherwise. The result of weak division depends on
+ the variable order. The covers on which Cudd_zddWeakDiv operates use
+ two ZDD variables for each function variable (one ZDD variable for
+ each literal of the variable). Those two ZDD variables should be
+ adjacent in the order.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddDivide]
+
+******************************************************************************/
+DdNode *
+Cudd_zddWeakDiv(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddZddWeakDiv(dd, f, g);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_zddWeakDiv */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the quotient of two unate covers.]
+
+ Description [Computes the quotient of two unate covers represented
+ by ZDDs. Unate covers use one ZDD variable for each BDD
+ variable. Returns a pointer to the resulting ZDD if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddWeakDiv]
+
+******************************************************************************/
+DdNode *
+Cudd_zddDivide(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddZddDivide(dd, f, g);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_zddDivide */
+
+
+/**Function********************************************************************
+
+ Synopsis [Modified version of Cudd_zddWeakDiv.]
+
+ Description [Modified version of Cudd_zddWeakDiv. This function may
+ disappear in future releases.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddWeakDiv]
+
+******************************************************************************/
+DdNode *
+Cudd_zddWeakDivF(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddZddWeakDivF(dd, f, g);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_zddWeakDivF */
+
+
+/**Function********************************************************************
+
+ Synopsis [Modified version of Cudd_zddDivide.]
+
+ Description [Modified version of Cudd_zddDivide. This function may
+ disappear in future releases.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_zddDivideF(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddZddDivideF(dd, f, g);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_zddDivideF */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes a complement cover for a ZDD node.]
+
+ Description [Computes a complement cover for a ZDD node. For lack of a
+ better method, we first extract the function BDD from the ZDD cover,
+ then make the complement of the ZDD cover from the complement of the
+ BDD node by using ISOP. Returns a pointer to the resulting cover if
+ successful; NULL otherwise. The result depends on current variable
+ order.]
+
+ SideEffects [The result depends on current variable order.]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_zddComplement(
+ DdManager *dd,
+ DdNode *node)
+{
+ DdNode *b, *isop, *zdd_I;
+
+ /* Check cache */
+ zdd_I = cuddCacheLookup1Zdd(dd, cuddZddComplement, node);
+ if (zdd_I)
+ return(zdd_I);
+
+ b = Cudd_MakeBddFromZddCover(dd, node);
+ if (!b)
+ return(NULL);
+ Cudd_Ref(b);
+ isop = Cudd_zddIsop(dd, Cudd_Not(b), Cudd_Not(b), &zdd_I);
+ if (!isop) {
+ Cudd_RecursiveDeref(dd, b);
+ return(NULL);
+ }
+ Cudd_Ref(isop);
+ Cudd_Ref(zdd_I);
+ Cudd_RecursiveDeref(dd, b);
+ Cudd_RecursiveDeref(dd, isop);
+
+ cuddCacheInsert1(dd, cuddZddComplement, node, zdd_I);
+ Cudd_Deref(zdd_I);
+ return(zdd_I);
+} /* end of Cudd_zddComplement */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddProduct.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddProduct]
+
+******************************************************************************/
+DdNode *
+cuddZddProduct(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ int v, top_f, top_g;
+ DdNode *tmp, *term1, *term2, *term3;
+ DdNode *f0, *f1, *fd, *g0, *g1, *gd;
+ DdNode *R0, *R1, *Rd, *N0, *N1;
+ DdNode *r;
+ DdNode *one = DD_ONE(dd);
+ DdNode *zero = DD_ZERO(dd);
+ int flag;
+ int pv, nv;
+
+ statLine(dd);
+ if (f == zero || g == zero)
+ return(zero);
+ if (f == one)
+ return(g);
+ if (g == one)
+ return(f);
+
+ top_f = dd->permZ[f->index];
+ top_g = dd->permZ[g->index];
+
+ if (top_f > top_g)
+ return(cuddZddProduct(dd, g, f));
+
+ /* Check cache */
+ r = cuddCacheLookup2Zdd(dd, cuddZddProduct, f, g);
+ if (r)
+ return(r);
+
+ v = f->index; /* either yi or zi */
+ flag = cuddZddGetCofactors3(dd, f, v, &f1, &f0, &fd);
+ if (flag == 1)
+ return(NULL);
+ Cudd_Ref(f1);
+ Cudd_Ref(f0);
+ Cudd_Ref(fd);
+ flag = cuddZddGetCofactors3(dd, g, v, &g1, &g0, &gd);
+ if (flag == 1) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ return(NULL);
+ }
+ Cudd_Ref(g1);
+ Cudd_Ref(g0);
+ Cudd_Ref(gd);
+ pv = cuddZddGetPosVarIndex(dd, v);
+ nv = cuddZddGetNegVarIndex(dd, v);
+
+ Rd = cuddZddProduct(dd, fd, gd);
+ if (Rd == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ return(NULL);
+ }
+ Cudd_Ref(Rd);
+
+ term1 = cuddZddProduct(dd, f0, g0);
+ if (term1 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ Cudd_RecursiveDerefZdd(dd, Rd);
+ return(NULL);
+ }
+ Cudd_Ref(term1);
+ term2 = cuddZddProduct(dd, f0, gd);
+ if (term2 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ Cudd_RecursiveDerefZdd(dd, Rd);
+ Cudd_RecursiveDerefZdd(dd, term1);
+ return(NULL);
+ }
+ Cudd_Ref(term2);
+ term3 = cuddZddProduct(dd, fd, g0);
+ if (term3 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ Cudd_RecursiveDerefZdd(dd, Rd);
+ Cudd_RecursiveDerefZdd(dd, term1);
+ Cudd_RecursiveDerefZdd(dd, term2);
+ return(NULL);
+ }
+ Cudd_Ref(term3);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ tmp = cuddZddUnion(dd, term1, term2);
+ if (tmp == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ Cudd_RecursiveDerefZdd(dd, Rd);
+ Cudd_RecursiveDerefZdd(dd, term1);
+ Cudd_RecursiveDerefZdd(dd, term2);
+ Cudd_RecursiveDerefZdd(dd, term3);
+ return(NULL);
+ }
+ Cudd_Ref(tmp);
+ Cudd_RecursiveDerefZdd(dd, term1);
+ Cudd_RecursiveDerefZdd(dd, term2);
+ R0 = cuddZddUnion(dd, tmp, term3);
+ if (R0 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ Cudd_RecursiveDerefZdd(dd, Rd);
+ Cudd_RecursiveDerefZdd(dd, term3);
+ Cudd_RecursiveDerefZdd(dd, tmp);
+ return(NULL);
+ }
+ Cudd_Ref(R0);
+ Cudd_RecursiveDerefZdd(dd, tmp);
+ Cudd_RecursiveDerefZdd(dd, term3);
+ N0 = cuddZddGetNode(dd, nv, R0, Rd); /* nv = zi */
+ if (N0 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ Cudd_RecursiveDerefZdd(dd, Rd);
+ Cudd_RecursiveDerefZdd(dd, R0);
+ return(NULL);
+ }
+ Cudd_Ref(N0);
+ Cudd_RecursiveDerefZdd(dd, R0);
+ Cudd_RecursiveDerefZdd(dd, Rd);
+
+ term1 = cuddZddProduct(dd, f1, g1);
+ if (term1 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ Cudd_RecursiveDerefZdd(dd, N0);
+ return(NULL);
+ }
+ Cudd_Ref(term1);
+ term2 = cuddZddProduct(dd, f1, gd);
+ if (term2 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ Cudd_RecursiveDerefZdd(dd, N0);
+ Cudd_RecursiveDerefZdd(dd, term1);
+ return(NULL);
+ }
+ Cudd_Ref(term2);
+ term3 = cuddZddProduct(dd, fd, g1);
+ if (term3 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ Cudd_RecursiveDerefZdd(dd, N0);
+ Cudd_RecursiveDerefZdd(dd, term1);
+ Cudd_RecursiveDerefZdd(dd, term2);
+ return(NULL);
+ }
+ Cudd_Ref(term3);
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ tmp = cuddZddUnion(dd, term1, term2);
+ if (tmp == NULL) {
+ Cudd_RecursiveDerefZdd(dd, N0);
+ Cudd_RecursiveDerefZdd(dd, term1);
+ Cudd_RecursiveDerefZdd(dd, term2);
+ Cudd_RecursiveDerefZdd(dd, term3);
+ return(NULL);
+ }
+ Cudd_Ref(tmp);
+ Cudd_RecursiveDerefZdd(dd, term1);
+ Cudd_RecursiveDerefZdd(dd, term2);
+ R1 = cuddZddUnion(dd, tmp, term3);
+ if (R1 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, N0);
+ Cudd_RecursiveDerefZdd(dd, term3);
+ Cudd_RecursiveDerefZdd(dd, tmp);
+ return(NULL);
+ }
+ Cudd_Ref(R1);
+ Cudd_RecursiveDerefZdd(dd, tmp);
+ Cudd_RecursiveDerefZdd(dd, term3);
+ N1 = cuddZddGetNode(dd, pv, R1, N0); /* pv = yi */
+ if (N1 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, N0);
+ Cudd_RecursiveDerefZdd(dd, R1);
+ return(NULL);
+ }
+ Cudd_Ref(N1);
+ Cudd_RecursiveDerefZdd(dd, R1);
+ Cudd_RecursiveDerefZdd(dd, N0);
+
+ cuddCacheInsert2(dd, cuddZddProduct, f, g, N1);
+ Cudd_Deref(N1);
+ return(N1);
+
+} /* end of cuddZddProduct */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddUnateProduct.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddUnateProduct]
+
+******************************************************************************/
+DdNode *
+cuddZddUnateProduct(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ int v, top_f, top_g;
+ DdNode *term1, *term2, *term3, *term4;
+ DdNode *sum1, *sum2;
+ DdNode *f0, *f1, *g0, *g1;
+ DdNode *r;
+ DdNode *one = DD_ONE(dd);
+ DdNode *zero = DD_ZERO(dd);
+ int flag;
+
+ statLine(dd);
+ if (f == zero || g == zero)
+ return(zero);
+ if (f == one)
+ return(g);
+ if (g == one)
+ return(f);
+
+ top_f = dd->permZ[f->index];
+ top_g = dd->permZ[g->index];
+
+ if (top_f > top_g)
+ return(cuddZddUnateProduct(dd, g, f));
+
+ /* Check cache */
+ r = cuddCacheLookup2Zdd(dd, cuddZddUnateProduct, f, g);
+ if (r)
+ return(r);
+
+ v = f->index; /* either yi or zi */
+ flag = cuddZddGetCofactors2(dd, f, v, &f1, &f0);
+ if (flag == 1)
+ return(NULL);
+ Cudd_Ref(f1);
+ Cudd_Ref(f0);
+ flag = cuddZddGetCofactors2(dd, g, v, &g1, &g0);
+ if (flag == 1) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ return(NULL);
+ }
+ Cudd_Ref(g1);
+ Cudd_Ref(g0);
+
+ term1 = cuddZddUnateProduct(dd, f1, g1);
+ if (term1 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ return(NULL);
+ }
+ Cudd_Ref(term1);
+ term2 = cuddZddUnateProduct(dd, f1, g0);
+ if (term2 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ Cudd_RecursiveDerefZdd(dd, term1);
+ return(NULL);
+ }
+ Cudd_Ref(term2);
+ term3 = cuddZddUnateProduct(dd, f0, g1);
+ if (term3 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ Cudd_RecursiveDerefZdd(dd, term1);
+ Cudd_RecursiveDerefZdd(dd, term2);
+ return(NULL);
+ }
+ Cudd_Ref(term3);
+ term4 = cuddZddUnateProduct(dd, f0, g0);
+ if (term4 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ Cudd_RecursiveDerefZdd(dd, term1);
+ Cudd_RecursiveDerefZdd(dd, term2);
+ Cudd_RecursiveDerefZdd(dd, term3);
+ return(NULL);
+ }
+ Cudd_Ref(term4);
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ sum1 = cuddZddUnion(dd, term1, term2);
+ if (sum1 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, term1);
+ Cudd_RecursiveDerefZdd(dd, term2);
+ Cudd_RecursiveDerefZdd(dd, term3);
+ Cudd_RecursiveDerefZdd(dd, term4);
+ return(NULL);
+ }
+ Cudd_Ref(sum1);
+ Cudd_RecursiveDerefZdd(dd, term1);
+ Cudd_RecursiveDerefZdd(dd, term2);
+ sum2 = cuddZddUnion(dd, sum1, term3);
+ if (sum2 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, term3);
+ Cudd_RecursiveDerefZdd(dd, term4);
+ Cudd_RecursiveDerefZdd(dd, sum1);
+ return(NULL);
+ }
+ Cudd_Ref(sum2);
+ Cudd_RecursiveDerefZdd(dd, sum1);
+ Cudd_RecursiveDerefZdd(dd, term3);
+ r = cuddZddGetNode(dd, v, sum2, term4);
+ if (r == NULL) {
+ Cudd_RecursiveDerefZdd(dd, term4);
+ Cudd_RecursiveDerefZdd(dd, sum2);
+ return(NULL);
+ }
+ Cudd_Ref(r);
+ Cudd_RecursiveDerefZdd(dd, sum2);
+ Cudd_RecursiveDerefZdd(dd, term4);
+
+ cuddCacheInsert2(dd, cuddZddUnateProduct, f, g, r);
+ Cudd_Deref(r);
+ return(r);
+
+} /* end of cuddZddUnateProduct */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddWeakDiv.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddWeakDiv]
+
+******************************************************************************/
+DdNode *
+cuddZddWeakDiv(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ int v;
+ DdNode *one = DD_ONE(dd);
+ DdNode *zero = DD_ZERO(dd);
+ DdNode *f0, *f1, *fd, *g0, *g1, *gd;
+ DdNode *q, *tmp;
+ DdNode *r;
+ int flag;
+
+ statLine(dd);
+ if (g == one)
+ return(f);
+ if (f == zero || f == one)
+ return(zero);
+ if (f == g)
+ return(one);
+
+ /* Check cache. */
+ r = cuddCacheLookup2Zdd(dd, cuddZddWeakDiv, f, g);
+ if (r)
+ return(r);
+
+ v = g->index;
+
+ flag = cuddZddGetCofactors3(dd, f, v, &f1, &f0, &fd);
+ if (flag == 1)
+ return(NULL);
+ Cudd_Ref(f1);
+ Cudd_Ref(f0);
+ Cudd_Ref(fd);
+ flag = cuddZddGetCofactors3(dd, g, v, &g1, &g0, &gd);
+ if (flag == 1) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ return(NULL);
+ }
+ Cudd_Ref(g1);
+ Cudd_Ref(g0);
+ Cudd_Ref(gd);
+
+ q = g;
+
+ if (g0 != zero) {
+ q = cuddZddWeakDiv(dd, f0, g0);
+ if (q == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ return(NULL);
+ }
+ Cudd_Ref(q);
+ }
+ else
+ Cudd_Ref(q);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g0);
+
+ if (q == zero) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ cuddCacheInsert2(dd, cuddZddWeakDiv, f, g, zero);
+ Cudd_Deref(q);
+ return(zero);
+ }
+
+ if (g1 != zero) {
+ Cudd_RecursiveDerefZdd(dd, q);
+ tmp = cuddZddWeakDiv(dd, f1, g1);
+ if (tmp == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ return(NULL);
+ }
+ Cudd_Ref(tmp);
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ if (q == g)
+ q = tmp;
+ else {
+ q = cuddZddIntersect(dd, q, tmp);
+ if (q == NULL) {
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ return(NULL);
+ }
+ Cudd_Ref(q);
+ Cudd_RecursiveDerefZdd(dd, tmp);
+ }
+ }
+ else {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ }
+
+ if (q == zero) {
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ cuddCacheInsert2(dd, cuddZddWeakDiv, f, g, zero);
+ Cudd_Deref(q);
+ return(zero);
+ }
+
+ if (gd != zero) {
+ Cudd_RecursiveDerefZdd(dd, q);
+ tmp = cuddZddWeakDiv(dd, fd, gd);
+ if (tmp == NULL) {
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ return(NULL);
+ }
+ Cudd_Ref(tmp);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ if (q == g)
+ q = tmp;
+ else {
+ q = cuddZddIntersect(dd, q, tmp);
+ if (q == NULL) {
+ Cudd_RecursiveDerefZdd(dd, tmp);
+ return(NULL);
+ }
+ Cudd_Ref(q);
+ Cudd_RecursiveDerefZdd(dd, tmp);
+ }
+ }
+ else {
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ }
+
+ cuddCacheInsert2(dd, cuddZddWeakDiv, f, g, q);
+ Cudd_Deref(q);
+ return(q);
+
+} /* end of cuddZddWeakDiv */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddWeakDivF.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddWeakDivF]
+
+******************************************************************************/
+DdNode *
+cuddZddWeakDivF(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ int v, top_f, top_g, vf, vg;
+ DdNode *one = DD_ONE(dd);
+ DdNode *zero = DD_ZERO(dd);
+ DdNode *f0, *f1, *fd, *g0, *g1, *gd;
+ DdNode *q, *tmp;
+ DdNode *r;
+ DdNode *term1, *term0, *termd;
+ int flag;
+ int pv, nv;
+
+ statLine(dd);
+ if (g == one)
+ return(f);
+ if (f == zero || f == one)
+ return(zero);
+ if (f == g)
+ return(one);
+
+ /* Check cache. */
+ r = cuddCacheLookup2Zdd(dd, cuddZddWeakDivF, f, g);
+ if (r)
+ return(r);
+
+ top_f = dd->permZ[f->index];
+ top_g = dd->permZ[g->index];
+ vf = top_f >> 1;
+ vg = top_g >> 1;
+ v = ddMin(top_f, top_g);
+
+ if (v == top_f && vf < vg) {
+ v = f->index;
+ flag = cuddZddGetCofactors3(dd, f, v, &f1, &f0, &fd);
+ if (flag == 1)
+ return(NULL);
+ Cudd_Ref(f1);
+ Cudd_Ref(f0);
+ Cudd_Ref(fd);
+
+ pv = cuddZddGetPosVarIndex(dd, v);
+ nv = cuddZddGetNegVarIndex(dd, v);
+
+ term1 = cuddZddWeakDivF(dd, f1, g);
+ if (term1 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ return(NULL);
+ }
+ Cudd_Ref(term1);
+ Cudd_RecursiveDerefZdd(dd, f1);
+ term0 = cuddZddWeakDivF(dd, f0, g);
+ if (term0 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, term1);
+ return(NULL);
+ }
+ Cudd_Ref(term0);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ termd = cuddZddWeakDivF(dd, fd, g);
+ if (termd == NULL) {
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, term1);
+ Cudd_RecursiveDerefZdd(dd, term0);
+ return(NULL);
+ }
+ Cudd_Ref(termd);
+ Cudd_RecursiveDerefZdd(dd, fd);
+
+ tmp = cuddZddGetNode(dd, nv, term0, termd); /* nv = zi */
+ if (tmp == NULL) {
+ Cudd_RecursiveDerefZdd(dd, term1);
+ Cudd_RecursiveDerefZdd(dd, term0);
+ Cudd_RecursiveDerefZdd(dd, termd);
+ return(NULL);
+ }
+ Cudd_Ref(tmp);
+ Cudd_RecursiveDerefZdd(dd, term0);
+ Cudd_RecursiveDerefZdd(dd, termd);
+ q = cuddZddGetNode(dd, pv, term1, tmp); /* pv = yi */
+ if (q == NULL) {
+ Cudd_RecursiveDerefZdd(dd, term1);
+ Cudd_RecursiveDerefZdd(dd, tmp);
+ return(NULL);
+ }
+ Cudd_Ref(q);
+ Cudd_RecursiveDerefZdd(dd, term1);
+ Cudd_RecursiveDerefZdd(dd, tmp);
+
+ cuddCacheInsert2(dd, cuddZddWeakDivF, f, g, q);
+ Cudd_Deref(q);
+ return(q);
+ }
+
+ if (v == top_f)
+ v = f->index;
+ else
+ v = g->index;
+
+ flag = cuddZddGetCofactors3(dd, f, v, &f1, &f0, &fd);
+ if (flag == 1)
+ return(NULL);
+ Cudd_Ref(f1);
+ Cudd_Ref(f0);
+ Cudd_Ref(fd);
+ flag = cuddZddGetCofactors3(dd, g, v, &g1, &g0, &gd);
+ if (flag == 1) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ return(NULL);
+ }
+ Cudd_Ref(g1);
+ Cudd_Ref(g0);
+ Cudd_Ref(gd);
+
+ q = g;
+
+ if (g0 != zero) {
+ q = cuddZddWeakDivF(dd, f0, g0);
+ if (q == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ return(NULL);
+ }
+ Cudd_Ref(q);
+ }
+ else
+ Cudd_Ref(q);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g0);
+
+ if (q == zero) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ cuddCacheInsert2(dd, cuddZddWeakDivF, f, g, zero);
+ Cudd_Deref(q);
+ return(zero);
+ }
+
+ if (g1 != zero) {
+ Cudd_RecursiveDerefZdd(dd, q);
+ tmp = cuddZddWeakDivF(dd, f1, g1);
+ if (tmp == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ return(NULL);
+ }
+ Cudd_Ref(tmp);
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ if (q == g)
+ q = tmp;
+ else {
+ q = cuddZddIntersect(dd, q, tmp);
+ if (q == NULL) {
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ return(NULL);
+ }
+ Cudd_Ref(q);
+ Cudd_RecursiveDerefZdd(dd, tmp);
+ }
+ }
+ else {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ }
+
+ if (q == zero) {
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ cuddCacheInsert2(dd, cuddZddWeakDivF, f, g, zero);
+ Cudd_Deref(q);
+ return(zero);
+ }
+
+ if (gd != zero) {
+ Cudd_RecursiveDerefZdd(dd, q);
+ tmp = cuddZddWeakDivF(dd, fd, gd);
+ if (tmp == NULL) {
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ return(NULL);
+ }
+ Cudd_Ref(tmp);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ if (q == g)
+ q = tmp;
+ else {
+ q = cuddZddIntersect(dd, q, tmp);
+ if (q == NULL) {
+ Cudd_RecursiveDerefZdd(dd, tmp);
+ return(NULL);
+ }
+ Cudd_Ref(q);
+ Cudd_RecursiveDerefZdd(dd, tmp);
+ }
+ }
+ else {
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDerefZdd(dd, gd);
+ }
+
+ cuddCacheInsert2(dd, cuddZddWeakDivF, f, g, q);
+ Cudd_Deref(q);
+ return(q);
+
+} /* end of cuddZddWeakDivF */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddDivide.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddDivide]
+
+******************************************************************************/
+DdNode *
+cuddZddDivide(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ int v;
+ DdNode *one = DD_ONE(dd);
+ DdNode *zero = DD_ZERO(dd);
+ DdNode *f0, *f1, *g0, *g1;
+ DdNode *q, *r, *tmp;
+ int flag;
+
+ statLine(dd);
+ if (g == one)
+ return(f);
+ if (f == zero || f == one)
+ return(zero);
+ if (f == g)
+ return(one);
+
+ /* Check cache. */
+ r = cuddCacheLookup2Zdd(dd, cuddZddDivide, f, g);
+ if (r)
+ return(r);
+
+ v = g->index;
+
+ flag = cuddZddGetCofactors2(dd, f, v, &f1, &f0);
+ if (flag == 1)
+ return(NULL);
+ Cudd_Ref(f1);
+ Cudd_Ref(f0);
+ flag = cuddZddGetCofactors2(dd, g, v, &g1, &g0); /* g1 != zero */
+ if (flag == 1) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ return(NULL);
+ }
+ Cudd_Ref(g1);
+ Cudd_Ref(g0);
+
+ r = cuddZddDivide(dd, f1, g1);
+ if (r == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ return(NULL);
+ }
+ Cudd_Ref(r);
+
+ if (r != zero && g0 != zero) {
+ tmp = r;
+ q = cuddZddDivide(dd, f0, g0);
+ if (q == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ return(NULL);
+ }
+ Cudd_Ref(q);
+ r = cuddZddIntersect(dd, r, q);
+ if (r == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ Cudd_RecursiveDerefZdd(dd, q);
+ return(NULL);
+ }
+ Cudd_Ref(r);
+ Cudd_RecursiveDerefZdd(dd, q);
+ Cudd_RecursiveDerefZdd(dd, tmp);
+ }
+
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+
+ cuddCacheInsert2(dd, cuddZddDivide, f, g, r);
+ Cudd_Deref(r);
+ return(r);
+
+} /* end of cuddZddDivide */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddDivideF.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddDivideF]
+
+******************************************************************************/
+DdNode *
+cuddZddDivideF(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g)
+{
+ int v;
+ DdNode *one = DD_ONE(dd);
+ DdNode *zero = DD_ZERO(dd);
+ DdNode *f0, *f1, *g0, *g1;
+ DdNode *q, *r, *tmp;
+ int flag;
+
+ statLine(dd);
+ if (g == one)
+ return(f);
+ if (f == zero || f == one)
+ return(zero);
+ if (f == g)
+ return(one);
+
+ /* Check cache. */
+ r = cuddCacheLookup2Zdd(dd, cuddZddDivideF, f, g);
+ if (r)
+ return(r);
+
+ v = g->index;
+
+ flag = cuddZddGetCofactors2(dd, f, v, &f1, &f0);
+ if (flag == 1)
+ return(NULL);
+ Cudd_Ref(f1);
+ Cudd_Ref(f0);
+ flag = cuddZddGetCofactors2(dd, g, v, &g1, &g0); /* g1 != zero */
+ if (flag == 1) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ return(NULL);
+ }
+ Cudd_Ref(g1);
+ Cudd_Ref(g0);
+
+ r = cuddZddDivideF(dd, f1, g1);
+ if (r == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ return(NULL);
+ }
+ Cudd_Ref(r);
+
+ if (r != zero && g0 != zero) {
+ tmp = r;
+ q = cuddZddDivideF(dd, f0, g0);
+ if (q == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ return(NULL);
+ }
+ Cudd_Ref(q);
+ r = cuddZddIntersect(dd, r, q);
+ if (r == NULL) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+ Cudd_RecursiveDerefZdd(dd, q);
+ return(NULL);
+ }
+ Cudd_Ref(r);
+ Cudd_RecursiveDerefZdd(dd, q);
+ Cudd_RecursiveDerefZdd(dd, tmp);
+ }
+
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, g1);
+ Cudd_RecursiveDerefZdd(dd, g0);
+
+ cuddCacheInsert2(dd, cuddZddDivideF, f, g, r);
+ Cudd_Deref(r);
+ return(r);
+
+} /* end of cuddZddDivideF */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the three-way decomposition of f w.r.t. v.]
+
+ Description [Computes the three-way decomposition of function f (represented
+ by a ZDD) wit respect to variable v.]
+
+ SideEffects [The results are returned in f1, f0, and fd.]
+
+ SeeAlso [cuddZddGetCofactors2]
+
+******************************************************************************/
+int
+cuddZddGetCofactors3(
+ DdManager * dd,
+ DdNode * f,
+ int v,
+ DdNode ** f1,
+ DdNode ** f0,
+ DdNode ** fd)
+{
+ DdNode *pc, *nc;
+ DdNode *zero = DD_ZERO(dd);
+ int top, hv, ht, pv, nv;
+ int level;
+
+ top = dd->permZ[f->index];
+ level = dd->permZ[v];
+ hv = level >> 1;
+ ht = top >> 1;
+
+ if (hv < ht) {
+ *f1 = zero;
+ *f0 = zero;
+ *fd = f;
+ }
+ else {
+ pv = cuddZddGetPosVarIndex(dd, v);
+ nv = cuddZddGetNegVarIndex(dd, v);
+
+ /* not to create intermediate ZDD node */
+ if (cuddZddGetPosVarLevel(dd, v) < cuddZddGetNegVarLevel(dd, v)) {
+ pc = cuddZddSubset1(dd, f, pv);
+ if (pc == NULL)
+ return(1);
+ Cudd_Ref(pc);
+ nc = cuddZddSubset0(dd, f, pv);
+ if (nc == NULL) {
+ Cudd_RecursiveDerefZdd(dd, pc);
+ return(1);
+ }
+ Cudd_Ref(nc);
+
+ *f1 = cuddZddSubset0(dd, pc, nv);
+ if (*f1 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, pc);
+ Cudd_RecursiveDerefZdd(dd, nc);
+ return(1);
+ }
+ Cudd_Ref(*f1);
+ *f0 = cuddZddSubset1(dd, nc, nv);
+ if (*f0 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, pc);
+ Cudd_RecursiveDerefZdd(dd, nc);
+ Cudd_RecursiveDerefZdd(dd, *f1);
+ return(1);
+ }
+ Cudd_Ref(*f0);
+
+ *fd = cuddZddSubset0(dd, nc, nv);
+ if (*fd == NULL) {
+ Cudd_RecursiveDerefZdd(dd, pc);
+ Cudd_RecursiveDerefZdd(dd, nc);
+ Cudd_RecursiveDerefZdd(dd, *f1);
+ Cudd_RecursiveDerefZdd(dd, *f0);
+ return(1);
+ }
+ Cudd_Ref(*fd);
+ } else {
+ pc = cuddZddSubset1(dd, f, nv);
+ if (pc == NULL)
+ return(1);
+ Cudd_Ref(pc);
+ nc = cuddZddSubset0(dd, f, nv);
+ if (nc == NULL) {
+ Cudd_RecursiveDerefZdd(dd, pc);
+ return(1);
+ }
+ Cudd_Ref(nc);
+
+ *f0 = cuddZddSubset0(dd, pc, pv);
+ if (*f0 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, pc);
+ Cudd_RecursiveDerefZdd(dd, nc);
+ return(1);
+ }
+ Cudd_Ref(*f0);
+ *f1 = cuddZddSubset1(dd, nc, pv);
+ if (*f1 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, pc);
+ Cudd_RecursiveDerefZdd(dd, nc);
+ Cudd_RecursiveDerefZdd(dd, *f1);
+ return(1);
+ }
+ Cudd_Ref(*f1);
+
+ *fd = cuddZddSubset0(dd, nc, pv);
+ if (*fd == NULL) {
+ Cudd_RecursiveDerefZdd(dd, pc);
+ Cudd_RecursiveDerefZdd(dd, nc);
+ Cudd_RecursiveDerefZdd(dd, *f1);
+ Cudd_RecursiveDerefZdd(dd, *f0);
+ return(1);
+ }
+ Cudd_Ref(*fd);
+ }
+
+ Cudd_RecursiveDerefZdd(dd, pc);
+ Cudd_RecursiveDerefZdd(dd, nc);
+ Cudd_Deref(*f1);
+ Cudd_Deref(*f0);
+ Cudd_Deref(*fd);
+ }
+ return(0);
+
+} /* end of cuddZddGetCofactors3 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the two-way decomposition of f w.r.t. v.]
+
+ Description []
+
+ SideEffects [The results are returned in f1 and f0.]
+
+ SeeAlso [cuddZddGetCofactors3]
+
+******************************************************************************/
+int
+cuddZddGetCofactors2(
+ DdManager * dd,
+ DdNode * f,
+ int v,
+ DdNode ** f1,
+ DdNode ** f0)
+{
+ *f1 = cuddZddSubset1(dd, f, v);
+ if (*f1 == NULL)
+ return(1);
+ *f0 = cuddZddSubset0(dd, f, v);
+ if (*f0 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, *f1);
+ return(1);
+ }
+ return(0);
+
+} /* end of cuddZddGetCofactors2 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes a complement of a ZDD node.]
+
+ Description [Computes the complement of a ZDD node. So far, since we
+ couldn't find a direct way to get the complement of a ZDD cover, we first
+ convert a ZDD cover to a BDD, then make the complement of the ZDD cover
+ from the complement of the BDD node by using ISOP.]
+
+ SideEffects [The result depends on current variable order.]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+cuddZddComplement(
+ DdManager * dd,
+ DdNode *node)
+{
+ DdNode *b, *isop, *zdd_I;
+
+ /* Check cache */
+ zdd_I = cuddCacheLookup1Zdd(dd, cuddZddComplement, node);
+ if (zdd_I)
+ return(zdd_I);
+
+ b = cuddMakeBddFromZddCover(dd, node);
+ if (!b)
+ return(NULL);
+ cuddRef(b);
+ isop = cuddZddIsop(dd, Cudd_Not(b), Cudd_Not(b), &zdd_I);
+ if (!isop) {
+ Cudd_RecursiveDeref(dd, b);
+ return(NULL);
+ }
+ cuddRef(isop);
+ cuddRef(zdd_I);
+ Cudd_RecursiveDeref(dd, b);
+ Cudd_RecursiveDeref(dd, isop);
+
+ cuddCacheInsert1(dd, cuddZddComplement, node, zdd_I);
+ cuddDeref(zdd_I);
+ return(zdd_I);
+} /* end of cuddZddComplement */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the index of positive ZDD variable.]
+
+ Description [Returns the index of positive ZDD variable.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddZddGetPosVarIndex(
+ DdManager * dd,
+ int index)
+{
+ int pv = (index >> 1) << 1;
+ return(pv);
+} /* end of cuddZddGetPosVarIndex */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the index of negative ZDD variable.]
+
+ Description [Returns the index of negative ZDD variable.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddZddGetNegVarIndex(
+ DdManager * dd,
+ int index)
+{
+ int nv = index | 0x1;
+ return(nv);
+} /* end of cuddZddGetPosVarIndex */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the level of positive ZDD variable.]
+
+ Description [Returns the level of positive ZDD variable.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddZddGetPosVarLevel(
+ DdManager * dd,
+ int index)
+{
+ int pv = cuddZddGetPosVarIndex(dd, index);
+ return(dd->permZ[pv]);
+} /* end of cuddZddGetPosVarLevel */
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the level of negative ZDD variable.]
+
+ Description [Returns the level of negative ZDD variable.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddZddGetNegVarLevel(
+ DdManager * dd,
+ int index)
+{
+ int nv = cuddZddGetNegVarIndex(dd, index);
+ return(dd->permZ[nv]);
+} /* end of cuddZddGetNegVarLevel */
diff --git a/src/bdd/cudd/cuddZddGroup.c b/src/bdd/cudd/cuddZddGroup.c
new file mode 100644
index 00000000..35f28881
--- /dev/null
+++ b/src/bdd/cudd/cuddZddGroup.c
@@ -0,0 +1,1317 @@
+/**CFile***********************************************************************
+
+ FileName [cuddZddGroup.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions for ZDD group sifting.]
+
+ Description [External procedures included in this file:
+ <ul>
+ <li> Cudd_MakeZddTreeNode()
+ </ul>
+ Internal procedures included in this file:
+ <ul>
+ <li> cuddZddTreeSifting()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> zddTreeSiftingAux()
+ <li> zddCountInternalMtrNodes()
+ <li> zddReorderChildren()
+ <li> zddFindNodeHiLo()
+ <li> zddUniqueCompareGroup()
+ <li> zddGroupSifting()
+ <li> zddGroupSiftingAux()
+ <li> zddGroupSiftingUp()
+ <li> zddGroupSiftingDown()
+ <li> zddGroupMove()
+ <li> zddGroupMoveBackward()
+ <li> zddGroupSiftingBackward()
+ <li> zddMergeGroups()
+ </ul>]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddZddGroup.c,v 1.1.1.1 2003/02/24 22:23:54 wjiang Exp $";
+#endif
+
+static int *entry;
+extern int zddTotalNumberSwapping;
+#ifdef DD_STATS
+static int extsymmcalls;
+static int extsymm;
+static int secdiffcalls;
+static int secdiff;
+static int secdiffmisfire;
+#endif
+#ifdef DD_DEBUG
+static int pr = 0; /* flag to enable printing while debugging */
+ /* by depositing a 1 into it */
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int zddTreeSiftingAux ARGS((DdManager *table, MtrNode *treenode, Cudd_ReorderingType method));
+#ifdef DD_STATS
+static int zddCountInternalMtrNodes ARGS((DdManager *table, MtrNode *treenode));
+#endif
+static int zddReorderChildren ARGS((DdManager *table, MtrNode *treenode, Cudd_ReorderingType method));
+static void zddFindNodeHiLo ARGS((DdManager *table, MtrNode *treenode, int *lower, int *upper));
+static int zddUniqueCompareGroup ARGS((int *ptrX, int *ptrY));
+static int zddGroupSifting ARGS((DdManager *table, int lower, int upper));
+static int zddGroupSiftingAux ARGS((DdManager *table, int x, int xLow, int xHigh));
+static int zddGroupSiftingUp ARGS((DdManager *table, int y, int xLow, Move **moves));
+static int zddGroupSiftingDown ARGS((DdManager *table, int x, int xHigh, Move **moves));
+static int zddGroupMove ARGS((DdManager *table, int x, int y, Move **moves));
+static int zddGroupMoveBackward ARGS((DdManager *table, int x, int y));
+static int zddGroupSiftingBackward ARGS((DdManager *table, Move *moves, int size));
+static void zddMergeGroups ARGS((DdManager *table, MtrNode *treenode, int low, int high));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Creates a new ZDD variable group.]
+
+ Description [Creates a new ZDD variable group. The group starts at
+ variable and contains size variables. The parameter low is the index
+ of the first variable. If the variable already exists, its current
+ position in the order is known to the manager. If the variable does
+ not exist yet, the position is assumed to be the same as the index.
+ The group tree is created if it does not exist yet.
+ Returns a pointer to the group if successful; NULL otherwise.]
+
+ SideEffects [The ZDD variable tree is changed.]
+
+ SeeAlso [Cudd_MakeTreeNode]
+
+******************************************************************************/
+MtrNode *
+Cudd_MakeZddTreeNode(
+ DdManager * dd /* manager */,
+ unsigned int low /* index of the first group variable */,
+ unsigned int size /* number of variables in the group */,
+ unsigned int type /* MTR_DEFAULT or MTR_FIXED */)
+{
+ MtrNode *group;
+ MtrNode *tree;
+ unsigned int level;
+
+ /* If the variable does not exist yet, the position is assumed to be
+ ** the same as the index. Therefore, applications that rely on
+ ** Cudd_bddNewVarAtLevel or Cudd_addNewVarAtLevel to create new
+ ** variables have to create the variables before they group them.
+ */
+ level = (low < (unsigned int) dd->sizeZ) ? dd->permZ[low] : low;
+
+ if (level + size - 1> (int) MTR_MAXHIGH)
+ return(NULL);
+
+ /* If the tree does not exist yet, create it. */
+ tree = dd->treeZ;
+ if (tree == NULL) {
+ dd->treeZ = tree = Mtr_InitGroupTree(0, dd->sizeZ);
+ if (tree == NULL)
+ return(NULL);
+ tree->index = dd->invpermZ[0];
+ }
+
+ /* Extend the upper bound of the tree if necessary. This allows the
+ ** application to create groups even before the variables are created.
+ */
+ tree->size = ddMax(tree->size, level + size);
+
+ /* Create the group. */
+ group = Mtr_MakeGroup(tree, level, size, type);
+ if (group == NULL)
+ return(NULL);
+
+ /* Initialize the index field to the index of the variable currently
+ ** in position low. This field will be updated by the reordering
+ ** procedure to provide a handle to the group once it has been moved.
+ */
+ group->index = (MtrHalfWord) low;
+
+ return(group);
+
+} /* end of Cudd_MakeZddTreeNode */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Tree sifting algorithm for ZDDs.]
+
+ Description [Tree sifting algorithm for ZDDs. Assumes that a tree
+ representing a group hierarchy is passed as a parameter. It then
+ reorders each group in postorder fashion by calling
+ zddTreeSiftingAux. Assumes that no dead nodes are present. Returns
+ 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+int
+cuddZddTreeSifting(
+ DdManager * table /* DD table */,
+ Cudd_ReorderingType method /* reordering method for the groups of leaves */)
+{
+ int i;
+ int nvars;
+ int result;
+ int tempTree;
+
+ /* If no tree is provided we create a temporary one in which all
+ ** variables are in a single group. After reordering this tree is
+ ** destroyed.
+ */
+ tempTree = table->treeZ == NULL;
+ if (tempTree) {
+ table->treeZ = Mtr_InitGroupTree(0,table->sizeZ);
+ table->treeZ->index = table->invpermZ[0];
+ }
+ nvars = table->sizeZ;
+
+#ifdef DD_DEBUG
+ if (pr > 0 && !tempTree)
+ (void) fprintf(table->out,"cuddZddTreeSifting:");
+ Mtr_PrintGroups(table->treeZ,pr <= 0);
+#endif
+#if 0
+ /* Debugging code. */
+ if (table->tree && table->treeZ) {
+ (void) fprintf(table->out,"\n");
+ Mtr_PrintGroups(table->tree, 0);
+ cuddPrintVarGroups(table,table->tree,0,0);
+ for (i = 0; i < table->size; i++) {
+ (void) fprintf(table->out,"%s%d",
+ (i == 0) ? "" : ",", table->invperm[i]);
+ }
+ (void) fprintf(table->out,"\n");
+ for (i = 0; i < table->size; i++) {
+ (void) fprintf(table->out,"%s%d",
+ (i == 0) ? "" : ",", table->perm[i]);
+ }
+ (void) fprintf(table->out,"\n\n");
+ Mtr_PrintGroups(table->treeZ,0);
+ cuddPrintVarGroups(table,table->treeZ,1,0);
+ for (i = 0; i < table->sizeZ; i++) {
+ (void) fprintf(table->out,"%s%d",
+ (i == 0) ? "" : ",", table->invpermZ[i]);
+ }
+ (void) fprintf(table->out,"\n");
+ for (i = 0; i < table->sizeZ; i++) {
+ (void) fprintf(table->out,"%s%d",
+ (i == 0) ? "" : ",", table->permZ[i]);
+ }
+ (void) fprintf(table->out,"\n");
+ }
+ /* End of debugging code. */
+#endif
+#ifdef DD_STATS
+ extsymmcalls = 0;
+ extsymm = 0;
+ secdiffcalls = 0;
+ secdiff = 0;
+ secdiffmisfire = 0;
+
+ (void) fprintf(table->out,"\n");
+ if (!tempTree)
+ (void) fprintf(table->out,"#:IM_NODES %8d: group tree nodes\n",
+ zddCountInternalMtrNodes(table,table->treeZ));
+#endif
+
+ /* Initialize the group of each subtable to itself. Initially
+ ** there are no groups. Groups are created according to the tree
+ ** structure in postorder fashion.
+ */
+ for (i = 0; i < nvars; i++)
+ table->subtableZ[i].next = i;
+
+ /* Reorder. */
+ result = zddTreeSiftingAux(table, table->treeZ, method);
+
+#ifdef DD_STATS /* print stats */
+ if (!tempTree && method == CUDD_REORDER_GROUP_SIFT &&
+ (table->groupcheck == CUDD_GROUP_CHECK7 ||
+ table->groupcheck == CUDD_GROUP_CHECK5)) {
+ (void) fprintf(table->out,"\nextsymmcalls = %d\n",extsymmcalls);
+ (void) fprintf(table->out,"extsymm = %d",extsymm);
+ }
+ if (!tempTree && method == CUDD_REORDER_GROUP_SIFT &&
+ table->groupcheck == CUDD_GROUP_CHECK7) {
+ (void) fprintf(table->out,"\nsecdiffcalls = %d\n",secdiffcalls);
+ (void) fprintf(table->out,"secdiff = %d\n",secdiff);
+ (void) fprintf(table->out,"secdiffmisfire = %d",secdiffmisfire);
+ }
+#endif
+
+ if (tempTree)
+ Cudd_FreeZddTree(table);
+ return(result);
+
+} /* end of cuddZddTreeSifting */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Visits the group tree and reorders each group.]
+
+ Description [Recursively visits the group tree and reorders each
+ group in postorder fashion. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+zddTreeSiftingAux(
+ DdManager * table,
+ MtrNode * treenode,
+ Cudd_ReorderingType method)
+{
+ MtrNode *auxnode;
+ int res;
+
+#ifdef DD_DEBUG
+ Mtr_PrintGroups(treenode,1);
+#endif
+
+ auxnode = treenode;
+ while (auxnode != NULL) {
+ if (auxnode->child != NULL) {
+ if (!zddTreeSiftingAux(table, auxnode->child, method))
+ return(0);
+ res = zddReorderChildren(table, auxnode, CUDD_REORDER_GROUP_SIFT);
+ if (res == 0)
+ return(0);
+ } else if (auxnode->size > 1) {
+ if (!zddReorderChildren(table, auxnode, method))
+ return(0);
+ }
+ auxnode = auxnode->younger;
+ }
+
+ return(1);
+
+} /* end of zddTreeSiftingAux */
+
+
+#ifdef DD_STATS
+/**Function********************************************************************
+
+ Synopsis [Counts the number of internal nodes of the group tree.]
+
+ Description [Counts the number of internal nodes of the group tree.
+ Returns the count.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+zddCountInternalMtrNodes(
+ DdManager * table,
+ MtrNode * treenode)
+{
+ MtrNode *auxnode;
+ int count,nodeCount;
+
+
+ nodeCount = 0;
+ auxnode = treenode;
+ while (auxnode != NULL) {
+ if (!(MTR_TEST(auxnode,MTR_TERMINAL))) {
+ nodeCount++;
+ count = zddCountInternalMtrNodes(table,auxnode->child);
+ nodeCount += count;
+ }
+ auxnode = auxnode->younger;
+ }
+
+ return(nodeCount);
+
+} /* end of zddCountInternalMtrNodes */
+#endif
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders the children of a group tree node according to
+ the options.]
+
+ Description [Reorders the children of a group tree node according to
+ the options. After reordering puts all the variables in the group
+ and/or its descendents in a single group. This allows hierarchical
+ reordering. If the variables in the group do not exist yet, simply
+ does nothing. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+zddReorderChildren(
+ DdManager * table,
+ MtrNode * treenode,
+ Cudd_ReorderingType method)
+{
+ int lower;
+ int upper;
+ int result;
+ unsigned int initialSize;
+
+ zddFindNodeHiLo(table,treenode,&lower,&upper);
+ /* If upper == -1 these variables do not exist yet. */
+ if (upper == -1)
+ return(1);
+
+ if (treenode->flags == MTR_FIXED) {
+ result = 1;
+ } else {
+#ifdef DD_STATS
+ (void) fprintf(table->out," ");
+#endif
+ switch (method) {
+ case CUDD_REORDER_RANDOM:
+ case CUDD_REORDER_RANDOM_PIVOT:
+ result = cuddZddSwapping(table,lower,upper,method);
+ break;
+ case CUDD_REORDER_SIFT:
+ result = cuddZddSifting(table,lower,upper);
+ break;
+ case CUDD_REORDER_SIFT_CONVERGE:
+ do {
+ initialSize = table->keysZ;
+ result = cuddZddSifting(table,lower,upper);
+ if (initialSize <= table->keysZ)
+ break;
+#ifdef DD_STATS
+ else
+ (void) fprintf(table->out,"\n");
+#endif
+ } while (result != 0);
+ break;
+ case CUDD_REORDER_SYMM_SIFT:
+ result = cuddZddSymmSifting(table,lower,upper);
+ break;
+ case CUDD_REORDER_SYMM_SIFT_CONV:
+ result = cuddZddSymmSiftingConv(table,lower,upper);
+ break;
+ case CUDD_REORDER_GROUP_SIFT:
+ result = zddGroupSifting(table,lower,upper);
+ break;
+ case CUDD_REORDER_LINEAR:
+ result = cuddZddLinearSifting(table,lower,upper);
+ break;
+ case CUDD_REORDER_LINEAR_CONVERGE:
+ do {
+ initialSize = table->keysZ;
+ result = cuddZddLinearSifting(table,lower,upper);
+ if (initialSize <= table->keysZ)
+ break;
+#ifdef DD_STATS
+ else
+ (void) fprintf(table->out,"\n");
+#endif
+ } while (result != 0);
+ break;
+ default:
+ return(0);
+ }
+ }
+
+ /* Create a single group for all the variables that were sifted,
+ ** so that they will be treated as a single block by successive
+ ** invocations of zddGroupSifting.
+ */
+ zddMergeGroups(table,treenode,lower,upper);
+
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,"zddReorderChildren:");
+#endif
+
+ return(result);
+
+} /* end of zddReorderChildren */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the lower and upper bounds of the group represented
+ by treenode.]
+
+ Description [Finds the lower and upper bounds of the group represented
+ by treenode. The high and low fields of treenode are indices. From
+ those we need to derive the current positions, and find maximum and
+ minimum.]
+
+ SideEffects [The bounds are returned as side effects.]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+zddFindNodeHiLo(
+ DdManager * table,
+ MtrNode * treenode,
+ int * lower,
+ int * upper)
+{
+ int low;
+ int high;
+
+ /* Check whether no variables in this group already exist.
+ ** If so, return immediately. The calling procedure will know from
+ ** the values of upper that no reordering is needed.
+ */
+ if ((int) treenode->low >= table->sizeZ) {
+ *lower = table->sizeZ;
+ *upper = -1;
+ return;
+ }
+
+ *lower = low = (unsigned int) table->permZ[treenode->index];
+ high = (int) (low + treenode->size - 1);
+
+ if (high >= table->sizeZ) {
+ /* This is the case of a partially existing group. The aim is to
+ ** reorder as many variables as safely possible. If the tree
+ ** node is terminal, we just reorder the subset of the group
+ ** that is currently in existence. If the group has
+ ** subgroups, then we only reorder those subgroups that are
+ ** fully instantiated. This way we avoid breaking up a group.
+ */
+ MtrNode *auxnode = treenode->child;
+ if (auxnode == NULL) {
+ *upper = (unsigned int) table->sizeZ - 1;
+ } else {
+ /* Search the subgroup that strands the table->sizeZ line.
+ ** If the first group starts at 0 and goes past table->sizeZ
+ ** upper will get -1, thus correctly signaling that no reordering
+ ** should take place.
+ */
+ while (auxnode != NULL) {
+ int thisLower = table->permZ[auxnode->low];
+ int thisUpper = thisLower + auxnode->size - 1;
+ if (thisUpper >= table->sizeZ && thisLower < table->sizeZ)
+ *upper = (unsigned int) thisLower - 1;
+ auxnode = auxnode->younger;
+ }
+ }
+ } else {
+ /* Normal case: All the variables of the group exist. */
+ *upper = (unsigned int) high;
+ }
+
+#ifdef DD_DEBUG
+ /* Make sure that all variables in group are contiguous. */
+ assert(treenode->size >= *upper - *lower + 1);
+#endif
+
+ return;
+
+} /* end of zddFindNodeHiLo */
+
+
+/**Function********************************************************************
+
+ Synopsis [Comparison function used by qsort.]
+
+ Description [Comparison function used by qsort to order the variables
+ according to the number of keys in the subtables. Returns the
+ difference in number of keys between the two variables being
+ compared.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+zddUniqueCompareGroup(
+ int * ptrX,
+ int * ptrY)
+{
+#if 0
+ if (entry[*ptrY] == entry[*ptrX]) {
+ return((*ptrX) - (*ptrY));
+ }
+#endif
+ return(entry[*ptrY] - entry[*ptrX]);
+
+} /* end of zddUniqueCompareGroup */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts from treenode->low to treenode->high.]
+
+ Description [Sifts from treenode->low to treenode->high. If
+ croupcheck == CUDD_GROUP_CHECK7, it checks for group creation at the
+ end of the initial sifting. If a group is created, it is then sifted
+ again. After sifting one variable, the group that contains it is
+ dissolved. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+zddGroupSifting(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int *var;
+ int i,j,x,xInit;
+ int nvars;
+ int classes;
+ int result;
+ int *sifted;
+#ifdef DD_STATS
+ unsigned previousSize;
+#endif
+ int xindex;
+
+ nvars = table->sizeZ;
+
+ /* Order variables to sift. */
+ entry = NULL;
+ sifted = NULL;
+ var = ALLOC(int,nvars);
+ if (var == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto zddGroupSiftingOutOfMem;
+ }
+ entry = ALLOC(int,nvars);
+ if (entry == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto zddGroupSiftingOutOfMem;
+ }
+ sifted = ALLOC(int,nvars);
+ if (sifted == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto zddGroupSiftingOutOfMem;
+ }
+
+ /* Here we consider only one representative for each group. */
+ for (i = 0, classes = 0; i < nvars; i++) {
+ sifted[i] = 0;
+ x = table->permZ[i];
+ if ((unsigned) x >= table->subtableZ[x].next) {
+ entry[i] = table->subtableZ[x].keys;
+ var[classes] = i;
+ classes++;
+ }
+ }
+
+ qsort((void *)var,classes,sizeof(int),(int (*)(const void *, const void *))zddUniqueCompareGroup);
+
+ /* Now sift. */
+ for (i = 0; i < ddMin(table->siftMaxVar,classes); i++) {
+ if (zddTotalNumberSwapping >= table->siftMaxSwap)
+ break;
+ xindex = var[i];
+ if (sifted[xindex] == 1) /* variable already sifted as part of group */
+ continue;
+ x = table->permZ[xindex]; /* find current level of this variable */
+ if (x < lower || x > upper)
+ continue;
+#ifdef DD_STATS
+ previousSize = table->keysZ;
+#endif
+#ifdef DD_DEBUG
+ /* x is bottom of group */
+ assert((unsigned) x >= table->subtableZ[x].next);
+#endif
+ result = zddGroupSiftingAux(table,x,lower,upper);
+ if (!result) goto zddGroupSiftingOutOfMem;
+
+#ifdef DD_STATS
+ if (table->keysZ < previousSize) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keysZ > previousSize) {
+ (void) fprintf(table->out,"+");
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+
+ /* Mark variables in the group just sifted. */
+ x = table->permZ[xindex];
+ if ((unsigned) x != table->subtableZ[x].next) {
+ xInit = x;
+ do {
+ j = table->invpermZ[x];
+ sifted[j] = 1;
+ x = table->subtableZ[x].next;
+ } while (x != xInit);
+ }
+
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,"zddGroupSifting:");
+#endif
+ } /* for */
+
+ FREE(sifted);
+ FREE(var);
+ FREE(entry);
+
+ return(1);
+
+zddGroupSiftingOutOfMem:
+ if (entry != NULL) FREE(entry);
+ if (var != NULL) FREE(var);
+ if (sifted != NULL) FREE(sifted);
+
+ return(0);
+
+} /* end of zddGroupSifting */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts one variable up and down until it has taken all
+ positions. Checks for aggregation.]
+
+ Description [Sifts one variable up and down until it has taken all
+ positions. Checks for aggregation. There may be at most two sweeps,
+ even if the group grows. Assumes that x is either an isolated
+ variable, or it is the bottom of a group. All groups may not have
+ been found. The variable being moved is returned to the best position
+ seen during sifting. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+zddGroupSiftingAux(
+ DdManager * table,
+ int x,
+ int xLow,
+ int xHigh)
+{
+ Move *move;
+ Move *moves; /* list of moves */
+ int initialSize;
+ int result;
+
+
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,"zddGroupSiftingAux from %d to %d\n",xLow,xHigh);
+ assert((unsigned) x >= table->subtableZ[x].next); /* x is bottom of group */
+#endif
+
+ initialSize = table->keysZ;
+ moves = NULL;
+
+ if (x == xLow) { /* Sift down */
+#ifdef DD_DEBUG
+ /* x must be a singleton */
+ assert((unsigned) x == table->subtableZ[x].next);
+#endif
+ if (x == xHigh) return(1); /* just one variable */
+
+ if (!zddGroupSiftingDown(table,x,xHigh,&moves))
+ goto zddGroupSiftingAuxOutOfMem;
+ /* at this point x == xHigh, unless early term */
+
+ /* move backward and stop at best position */
+ result = zddGroupSiftingBackward(table,moves,initialSize);
+#ifdef DD_DEBUG
+ assert(table->keysZ <= (unsigned) initialSize);
+#endif
+ if (!result) goto zddGroupSiftingAuxOutOfMem;
+
+ } else if (cuddZddNextHigh(table,x) > xHigh) { /* Sift up */
+#ifdef DD_DEBUG
+ /* x is bottom of group */
+ assert((unsigned) x >= table->subtableZ[x].next);
+#endif
+ /* Find top of x's group */
+ x = table->subtableZ[x].next;
+
+ if (!zddGroupSiftingUp(table,x,xLow,&moves))
+ goto zddGroupSiftingAuxOutOfMem;
+ /* at this point x == xLow, unless early term */
+
+ /* move backward and stop at best position */
+ result = zddGroupSiftingBackward(table,moves,initialSize);
+#ifdef DD_DEBUG
+ assert(table->keysZ <= (unsigned) initialSize);
+#endif
+ if (!result) goto zddGroupSiftingAuxOutOfMem;
+
+ } else if (x - xLow > xHigh - x) { /* must go down first: shorter */
+ if (!zddGroupSiftingDown(table,x,xHigh,&moves))
+ goto zddGroupSiftingAuxOutOfMem;
+ /* at this point x == xHigh, unless early term */
+
+ /* Find top of group */
+ if (moves) {
+ x = moves->y;
+ }
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ x = table->subtableZ[x].next;
+#ifdef DD_DEBUG
+ /* x should be the top of a group */
+ assert((unsigned) x <= table->subtableZ[x].next);
+#endif
+
+ if (!zddGroupSiftingUp(table,x,xLow,&moves))
+ goto zddGroupSiftingAuxOutOfMem;
+
+ /* move backward and stop at best position */
+ result = zddGroupSiftingBackward(table,moves,initialSize);
+#ifdef DD_DEBUG
+ assert(table->keysZ <= (unsigned) initialSize);
+#endif
+ if (!result) goto zddGroupSiftingAuxOutOfMem;
+
+ } else { /* moving up first: shorter */
+ /* Find top of x's group */
+ x = table->subtableZ[x].next;
+
+ if (!zddGroupSiftingUp(table,x,xLow,&moves))
+ goto zddGroupSiftingAuxOutOfMem;
+ /* at this point x == xHigh, unless early term */
+
+ if (moves) {
+ x = moves->x;
+ }
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+#ifdef DD_DEBUG
+ /* x is bottom of a group */
+ assert((unsigned) x >= table->subtableZ[x].next);
+#endif
+
+ if (!zddGroupSiftingDown(table,x,xHigh,&moves))
+ goto zddGroupSiftingAuxOutOfMem;
+
+ /* move backward and stop at best position */
+ result = zddGroupSiftingBackward(table,moves,initialSize);
+#ifdef DD_DEBUG
+ assert(table->keysZ <= (unsigned) initialSize);
+#endif
+ if (!result) goto zddGroupSiftingAuxOutOfMem;
+ }
+
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+
+ return(1);
+
+zddGroupSiftingAuxOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+
+ return(0);
+
+} /* end of zddGroupSiftingAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts up a variable until either it reaches position xLow
+ or the size of the DD heap increases too much.]
+
+ Description [Sifts up a variable until either it reaches position
+ xLow or the size of the DD heap increases too much. Assumes that y is
+ the top of a group (or a singleton). Checks y for aggregation to the
+ adjacent variables. Records all the moves that are appended to the
+ list of moves received as input and returned as a side effect.
+ Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+zddGroupSiftingUp(
+ DdManager * table,
+ int y,
+ int xLow,
+ Move ** moves)
+{
+ Move *move;
+ int x;
+ int size;
+ int gxtop;
+ int limitSize;
+ int xindex, yindex;
+
+ yindex = table->invpermZ[y];
+
+ limitSize = table->keysZ;
+
+ x = cuddZddNextLow(table,y);
+ while (x >= xLow) {
+ gxtop = table->subtableZ[x].next;
+ if (table->subtableZ[x].next == (unsigned) x &&
+ table->subtableZ[y].next == (unsigned) y) {
+ /* x and y are self groups */
+ xindex = table->invpermZ[x];
+ size = cuddZddSwapInPlace(table,x,y);
+#ifdef DD_DEBUG
+ assert(table->subtableZ[x].next == (unsigned) x);
+ assert(table->subtableZ[y].next == (unsigned) y);
+#endif
+ if (size == 0) goto zddGroupSiftingUpOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL) goto zddGroupSiftingUpOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->flags = MTR_DEFAULT;
+ move->size = size;
+ move->next = *moves;
+ *moves = move;
+
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,"zddGroupSiftingUp (2 single groups):\n");
+#endif
+ if ((double) size > (double) limitSize * table->maxGrowth)
+ return(1);
+ if (size < limitSize) limitSize = size;
+ } else { /* group move */
+ size = zddGroupMove(table,x,y,moves);
+ if (size == 0) goto zddGroupSiftingUpOutOfMem;
+ if ((double) size > (double) limitSize * table->maxGrowth)
+ return(1);
+ if (size < limitSize) limitSize = size;
+ }
+ y = gxtop;
+ x = cuddZddNextLow(table,y);
+ }
+
+ return(1);
+
+zddGroupSiftingUpOutOfMem:
+ while (*moves != NULL) {
+ move = (*moves)->next;
+ cuddDeallocNode(table, (DdNode *) *moves);
+ *moves = move;
+ }
+ return(0);
+
+} /* end of zddGroupSiftingUp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts down a variable until it reaches position xHigh.]
+
+ Description [Sifts down a variable until it reaches position xHigh.
+ Assumes that x is the bottom of a group (or a singleton). Records
+ all the moves. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+zddGroupSiftingDown(
+ DdManager * table,
+ int x,
+ int xHigh,
+ Move ** moves)
+{
+ Move *move;
+ int y;
+ int size;
+ int limitSize;
+ int gxtop,gybot;
+ int xindex;
+
+
+ /* Initialize R */
+ xindex = table->invpermZ[x];
+ gxtop = table->subtableZ[x].next;
+ limitSize = size = table->keysZ;
+ y = cuddZddNextHigh(table,x);
+ while (y <= xHigh) {
+ /* Find bottom of y group. */
+ gybot = table->subtableZ[y].next;
+ while (table->subtableZ[gybot].next != (unsigned) y)
+ gybot = table->subtableZ[gybot].next;
+
+ if (table->subtableZ[x].next == (unsigned) x &&
+ table->subtableZ[y].next == (unsigned) y) {
+ /* x and y are self groups */
+ size = cuddZddSwapInPlace(table,x,y);
+#ifdef DD_DEBUG
+ assert(table->subtableZ[x].next == (unsigned) x);
+ assert(table->subtableZ[y].next == (unsigned) y);
+#endif
+ if (size == 0) goto zddGroupSiftingDownOutOfMem;
+
+ /* Record move. */
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto zddGroupSiftingDownOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->flags = MTR_DEFAULT;
+ move->size = size;
+ move->next = *moves;
+ *moves = move;
+
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,"zddGroupSiftingDown (2 single groups):\n");
+#endif
+ if ((double) size > (double) limitSize * table->maxGrowth)
+ return(1);
+ if (size < limitSize) limitSize = size;
+ x = y;
+ y = cuddZddNextHigh(table,x);
+ } else { /* Group move */
+ size = zddGroupMove(table,x,y,moves);
+ if (size == 0) goto zddGroupSiftingDownOutOfMem;
+ if ((double) size > (double) limitSize * table->maxGrowth)
+ return(1);
+ if (size < limitSize) limitSize = size;
+ }
+ x = gybot;
+ y = cuddZddNextHigh(table,x);
+ }
+
+ return(1);
+
+zddGroupSiftingDownOutOfMem:
+ while (*moves != NULL) {
+ move = (*moves)->next;
+ cuddDeallocNode(table, (DdNode *) *moves);
+ *moves = move;
+ }
+
+ return(0);
+
+} /* end of zddGroupSiftingDown */
+
+
+/**Function********************************************************************
+
+ Synopsis [Swaps two groups and records the move.]
+
+ Description [Swaps two groups and records the move. Returns the
+ number of keys in the DD table in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+zddGroupMove(
+ DdManager * table,
+ int x,
+ int y,
+ Move ** moves)
+{
+ Move *move;
+ int size;
+ int i,j,xtop,xbot,xsize,ytop,ybot,ysize,newxtop;
+ int swapx,swapy;
+#if defined(DD_DEBUG) && defined(DD_VERBOSE)
+ int initialSize,bestSize;
+#endif
+
+#if DD_DEBUG
+ /* We assume that x < y */
+ assert(x < y);
+#endif
+ /* Find top, bottom, and size for the two groups. */
+ xbot = x;
+ xtop = table->subtableZ[x].next;
+ xsize = xbot - xtop + 1;
+ ybot = y;
+ while ((unsigned) ybot < table->subtableZ[ybot].next)
+ ybot = table->subtableZ[ybot].next;
+ ytop = y;
+ ysize = ybot - ytop + 1;
+
+#if defined(DD_DEBUG) && defined(DD_VERBOSE)
+ initialSize = bestSize = table->keysZ;
+#endif
+ /* Sift the variables of the second group up through the first group */
+ for (i = 1; i <= ysize; i++) {
+ for (j = 1; j <= xsize; j++) {
+ size = cuddZddSwapInPlace(table,x,y);
+ if (size == 0) goto zddGroupMoveOutOfMem;
+#if defined(DD_DEBUG) && defined(DD_VERBOSE)
+ if (size < bestSize)
+ bestSize = size;
+#endif
+ swapx = x; swapy = y;
+ y = x;
+ x = cuddZddNextLow(table,y);
+ }
+ y = ytop + i;
+ x = cuddZddNextLow(table,y);
+ }
+#if defined(DD_DEBUG) && defined(DD_VERBOSE)
+ if ((bestSize < initialSize) && (bestSize < size))
+ (void) fprintf(table->out,"Missed local minimum: initialSize:%d bestSize:%d finalSize:%d\n",initialSize,bestSize,size);
+#endif
+
+ /* fix groups */
+ y = xtop; /* ytop is now where xtop used to be */
+ for (i = 0; i < ysize - 1; i++) {
+ table->subtableZ[y].next = cuddZddNextHigh(table,y);
+ y = cuddZddNextHigh(table,y);
+ }
+ table->subtableZ[y].next = xtop; /* y is bottom of its group, join */
+ /* it to top of its group */
+ x = cuddZddNextHigh(table,y);
+ newxtop = x;
+ for (i = 0; i < xsize - 1; i++) {
+ table->subtableZ[x].next = cuddZddNextHigh(table,x);
+ x = cuddZddNextHigh(table,x);
+ }
+ table->subtableZ[x].next = newxtop; /* x is bottom of its group, join */
+ /* it to top of its group */
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,"zddGroupMove:\n");
+#endif
+
+ /* Store group move */
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL) goto zddGroupMoveOutOfMem;
+ move->x = swapx;
+ move->y = swapy;
+ move->flags = MTR_DEFAULT;
+ move->size = table->keysZ;
+ move->next = *moves;
+ *moves = move;
+
+ return(table->keysZ);
+
+zddGroupMoveOutOfMem:
+ while (*moves != NULL) {
+ move = (*moves)->next;
+ cuddDeallocNode(table, (DdNode *) *moves);
+ *moves = move;
+ }
+ return(0);
+
+} /* end of zddGroupMove */
+
+
+/**Function********************************************************************
+
+ Synopsis [Undoes the swap two groups.]
+
+ Description [Undoes the swap two groups. Returns 1 in case of
+ success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+zddGroupMoveBackward(
+ DdManager * table,
+ int x,
+ int y)
+{
+ int size;
+ int i,j,xtop,xbot,xsize,ytop,ybot,ysize,newxtop;
+
+
+#if DD_DEBUG
+ /* We assume that x < y */
+ assert(x < y);
+#endif
+
+ /* Find top, bottom, and size for the two groups. */
+ xbot = x;
+ xtop = table->subtableZ[x].next;
+ xsize = xbot - xtop + 1;
+ ybot = y;
+ while ((unsigned) ybot < table->subtableZ[ybot].next)
+ ybot = table->subtableZ[ybot].next;
+ ytop = y;
+ ysize = ybot - ytop + 1;
+
+ /* Sift the variables of the second group up through the first group */
+ for (i = 1; i <= ysize; i++) {
+ for (j = 1; j <= xsize; j++) {
+ size = cuddZddSwapInPlace(table,x,y);
+ if (size == 0)
+ return(0);
+ y = x;
+ x = cuddZddNextLow(table,y);
+ }
+ y = ytop + i;
+ x = cuddZddNextLow(table,y);
+ }
+
+ /* fix groups */
+ y = xtop;
+ for (i = 0; i < ysize - 1; i++) {
+ table->subtableZ[y].next = cuddZddNextHigh(table,y);
+ y = cuddZddNextHigh(table,y);
+ }
+ table->subtableZ[y].next = xtop; /* y is bottom of its group, join */
+ /* to its top */
+ x = cuddZddNextHigh(table,y);
+ newxtop = x;
+ for (i = 0; i < xsize - 1; i++) {
+ table->subtableZ[x].next = cuddZddNextHigh(table,x);
+ x = cuddZddNextHigh(table,x);
+ }
+ table->subtableZ[x].next = newxtop; /* x is bottom of its group, join */
+ /* to its top */
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,"zddGroupMoveBackward:\n");
+#endif
+
+ return(1);
+
+} /* end of zddGroupMoveBackward */
+
+
+/**Function********************************************************************
+
+ Synopsis [Determines the best position for a variables and returns
+ it there.]
+
+ Description [Determines the best position for a variables and returns
+ it there. Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+zddGroupSiftingBackward(
+ DdManager * table,
+ Move * moves,
+ int size)
+{
+ Move *move;
+ int res;
+
+
+ for (move = moves; move != NULL; move = move->next) {
+ if (move->size < size) {
+ size = move->size;
+ }
+ }
+
+ for (move = moves; move != NULL; move = move->next) {
+ if (move->size == size) return(1);
+ if ((table->subtableZ[move->x].next == move->x) &&
+ (table->subtableZ[move->y].next == move->y)) {
+ res = cuddZddSwapInPlace(table,(int)move->x,(int)move->y);
+ if (!res) return(0);
+#ifdef DD_DEBUG
+ if (pr > 0) (void) fprintf(table->out,"zddGroupSiftingBackward:\n");
+ assert(table->subtableZ[move->x].next == move->x);
+ assert(table->subtableZ[move->y].next == move->y);
+#endif
+ } else { /* Group move necessary */
+ res = zddGroupMoveBackward(table,(int)move->x,(int)move->y);
+ if (!res) return(0);
+ }
+ }
+
+ return(1);
+
+} /* end of zddGroupSiftingBackward */
+
+
+/**Function********************************************************************
+
+ Synopsis [Merges groups in the DD table.]
+
+ Description [Creates a single group from low to high and adjusts the
+ idex field of the tree node.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static void
+zddMergeGroups(
+ DdManager * table,
+ MtrNode * treenode,
+ int low,
+ int high)
+{
+ int i;
+ MtrNode *auxnode;
+ int saveindex;
+ int newindex;
+
+ /* Merge all variables from low to high in one group, unless
+ ** this is the topmost group. In such a case we do not merge lest
+ ** we lose the symmetry information. */
+ if (treenode != table->treeZ) {
+ for (i = low; i < high; i++)
+ table->subtableZ[i].next = i+1;
+ table->subtableZ[high].next = low;
+ }
+
+ /* Adjust the index fields of the tree nodes. If a node is the
+ ** first child of its parent, then the parent may also need adjustment. */
+ saveindex = treenode->index;
+ newindex = table->invpermZ[low];
+ auxnode = treenode;
+ do {
+ auxnode->index = newindex;
+ if (auxnode->parent == NULL ||
+ (int) auxnode->parent->index != saveindex)
+ break;
+ auxnode = auxnode->parent;
+ } while (1);
+ return;
+
+} /* end of zddMergeGroups */
+
diff --git a/src/bdd/cudd/cuddZddIsop.c b/src/bdd/cudd/cuddZddIsop.c
new file mode 100644
index 00000000..0918461c
--- /dev/null
+++ b/src/bdd/cudd/cuddZddIsop.c
@@ -0,0 +1,885 @@
+/**CFile***********************************************************************
+
+ FileName [cuddZddIsop.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions to find irredundant SOP covers as ZDDs from BDDs.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_bddIsop()
+ <li> Cudd_zddIsop()
+ <li> Cudd_MakeBddFromZddCover()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddBddIsop()
+ <li> cuddZddIsop()
+ <li> cuddMakeBddFromZddCover()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [In-Ho Moon]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddZddIsop.c,v 1.1.1.1 2003/02/24 22:23:54 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticEnd***************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Computes an ISOP in ZDD form from BDDs.]
+
+ Description [Computes an irredundant sum of products (ISOP) in ZDD
+ form from BDDs. The two BDDs L and U represent the lower bound and
+ the upper bound, respectively, of the function. The ISOP uses two
+ ZDD variables for each BDD variable: One for the positive literal,
+ and one for the negative literal. These two variables should be
+ adjacent in the ZDD order. The two ZDD variables corresponding to
+ BDD variable <code>i</code> should have indices <code>2i</code> and
+ <code>2i+1</code>. The result of this procedure depends on the
+ variable order. If successful, Cudd_zddIsop returns the BDD for
+ the function chosen from the interval. The ZDD representing the
+ irredundant cover is returned as a side effect in zdd_I. In case of
+ failure, NULL is returned.]
+
+ SideEffects [zdd_I holds the pointer to the ZDD for the ISOP on
+ successful return.]
+
+ SeeAlso [Cudd_bddIsop Cudd_zddVarsFromBddVars]
+
+******************************************************************************/
+DdNode *
+Cudd_zddIsop(
+ DdManager * dd,
+ DdNode * L,
+ DdNode * U,
+ DdNode ** zdd_I)
+{
+ DdNode *res;
+ int autoDynZ;
+
+ autoDynZ = dd->autoDynZ;
+ dd->autoDynZ = 0;
+
+ do {
+ dd->reordered = 0;
+ res = cuddZddIsop(dd, L, U, zdd_I);
+ } while (dd->reordered == 1);
+ dd->autoDynZ = autoDynZ;
+ return(res);
+
+} /* end of Cudd_zddIsop */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes a BDD in the interval between L and U with a
+ simple sum-of-produuct cover.]
+
+ Description [Computes a BDD in the interval between L and U with a
+ simple sum-of-produuct cover. This procedure is similar to
+ Cudd_zddIsop, but it does not return the ZDD for the cover. Returns
+ a pointer to the BDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddIsop]
+
+******************************************************************************/
+DdNode *
+Cudd_bddIsop(
+ DdManager * dd,
+ DdNode * L,
+ DdNode * U)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddIsop(dd, L, U);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddIsop */
+
+
+/**Function********************************************************************
+
+ Synopsis [Converts a ZDD cover to a BDD graph.]
+
+ Description [Converts a ZDD cover to a BDD graph. If successful, it
+ returns a BDD node, otherwise it returns NULL.]
+
+ SideEffects []
+
+ SeeAlso [cuddMakeBddFromZddCover]
+
+******************************************************************************/
+DdNode *
+Cudd_MakeBddFromZddCover(
+ DdManager * dd,
+ DdNode * node)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddMakeBddFromZddCover(dd, node);
+ } while (dd->reordered == 1);
+ return(res);
+} /* end of Cudd_MakeBddFromZddCover */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddIsop.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddIsop]
+
+******************************************************************************/
+DdNode *
+cuddZddIsop(
+ DdManager * dd,
+ DdNode * L,
+ DdNode * U,
+ DdNode ** zdd_I)
+{
+ DdNode *one = DD_ONE(dd);
+ DdNode *zero = Cudd_Not(one);
+ DdNode *zdd_one = DD_ONE(dd);
+ DdNode *zdd_zero = DD_ZERO(dd);
+ int v, top_l, top_u;
+ DdNode *Lsub0, *Usub0, *Lsub1, *Usub1, *Ld, *Ud;
+ DdNode *Lsuper0, *Usuper0, *Lsuper1, *Usuper1;
+ DdNode *Isub0, *Isub1, *Id;
+ DdNode *zdd_Isub0, *zdd_Isub1, *zdd_Id;
+ DdNode *x;
+ DdNode *term0, *term1, *sum;
+ DdNode *Lv, *Uv, *Lnv, *Unv;
+ DdNode *r, *y, *z;
+ int index;
+ DdNode *(*cacheOp)(DdManager *, DdNode *, DdNode *);
+
+ statLine(dd);
+ if (L == zero) {
+ *zdd_I = zdd_zero;
+ return(zero);
+ }
+ if (U == one) {
+ *zdd_I = zdd_one;
+ return(one);
+ }
+
+ if (U == zero || L == one) {
+ printf("*** ERROR : illegal condition for ISOP (U < L).\n");
+ exit(1);
+ }
+
+ /* Check the cache. We store two results for each recursive call.
+ ** One is the BDD, and the other is the ZDD. Both are needed.
+ ** Hence we need a double hit in the cache to terminate the
+ ** recursion. Clearly, collisions may evict only one of the two
+ ** results. */
+ cacheOp = (DdNode *(*)(DdManager *, DdNode *, DdNode *)) cuddZddIsop;
+ r = cuddCacheLookup2(dd, cuddBddIsop, L, U);
+ if (r) {
+ *zdd_I = cuddCacheLookup2Zdd(dd, cacheOp, L, U);
+ if (*zdd_I)
+ return(r);
+ else {
+ /* The BDD result may have been dead. In that case
+ ** cuddCacheLookup2 would have called cuddReclaim,
+ ** whose effects we now have to undo. */
+ cuddRef(r);
+ Cudd_RecursiveDeref(dd, r);
+ }
+ }
+
+ top_l = dd->perm[Cudd_Regular(L)->index];
+ top_u = dd->perm[Cudd_Regular(U)->index];
+ v = ddMin(top_l, top_u);
+
+ /* Compute cofactors. */
+ if (top_l == v) {
+ index = Cudd_Regular(L)->index;
+ Lv = Cudd_T(L);
+ Lnv = Cudd_E(L);
+ if (Cudd_IsComplement(L)) {
+ Lv = Cudd_Not(Lv);
+ Lnv = Cudd_Not(Lnv);
+ }
+ }
+ else {
+ index = Cudd_Regular(U)->index;
+ Lv = Lnv = L;
+ }
+
+ if (top_u == v) {
+ Uv = Cudd_T(U);
+ Unv = Cudd_E(U);
+ if (Cudd_IsComplement(U)) {
+ Uv = Cudd_Not(Uv);
+ Unv = Cudd_Not(Unv);
+ }
+ }
+ else {
+ Uv = Unv = U;
+ }
+
+ Lsub0 = cuddBddAndRecur(dd, Lnv, Cudd_Not(Uv));
+ if (Lsub0 == NULL)
+ return(NULL);
+ Cudd_Ref(Lsub0);
+ Usub0 = Unv;
+ Lsub1 = cuddBddAndRecur(dd, Lv, Cudd_Not(Unv));
+ if (Lsub1 == NULL) {
+ Cudd_RecursiveDeref(dd, Lsub0);
+ return(NULL);
+ }
+ Cudd_Ref(Lsub1);
+ Usub1 = Uv;
+
+ Isub0 = cuddZddIsop(dd, Lsub0, Usub0, &zdd_Isub0);
+ if (Isub0 == NULL) {
+ Cudd_RecursiveDeref(dd, Lsub0);
+ Cudd_RecursiveDeref(dd, Lsub1);
+ return(NULL);
+ }
+ /*
+ if ((!cuddIsConstant(Cudd_Regular(Isub0))) &&
+ (Cudd_Regular(Isub0)->index != zdd_Isub0->index / 2 ||
+ dd->permZ[index * 2] > dd->permZ[zdd_Isub0->index])) {
+ printf("*** ERROR : illegal permutation in ZDD. ***\n");
+ }
+ */
+ Cudd_Ref(Isub0);
+ Cudd_Ref(zdd_Isub0);
+ Isub1 = cuddZddIsop(dd, Lsub1, Usub1, &zdd_Isub1);
+ if (Isub1 == NULL) {
+ Cudd_RecursiveDeref(dd, Lsub0);
+ Cudd_RecursiveDeref(dd, Lsub1);
+ Cudd_RecursiveDeref(dd, Isub0);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub0);
+ return(NULL);
+ }
+ /*
+ if ((!cuddIsConstant(Cudd_Regular(Isub1))) &&
+ (Cudd_Regular(Isub1)->index != zdd_Isub1->index / 2 ||
+ dd->permZ[index * 2] > dd->permZ[zdd_Isub1->index])) {
+ printf("*** ERROR : illegal permutation in ZDD. ***\n");
+ }
+ */
+ Cudd_Ref(Isub1);
+ Cudd_Ref(zdd_Isub1);
+ Cudd_RecursiveDeref(dd, Lsub0);
+ Cudd_RecursiveDeref(dd, Lsub1);
+
+ Lsuper0 = cuddBddAndRecur(dd, Lnv, Cudd_Not(Isub0));
+ if (Lsuper0 == NULL) {
+ Cudd_RecursiveDeref(dd, Isub0);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub0);
+ Cudd_RecursiveDeref(dd, Isub1);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub1);
+ return(NULL);
+ }
+ Cudd_Ref(Lsuper0);
+ Lsuper1 = cuddBddAndRecur(dd, Lv, Cudd_Not(Isub1));
+ if (Lsuper1 == NULL) {
+ Cudd_RecursiveDeref(dd, Isub0);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub0);
+ Cudd_RecursiveDeref(dd, Isub1);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub1);
+ Cudd_RecursiveDeref(dd, Lsuper0);
+ return(NULL);
+ }
+ Cudd_Ref(Lsuper1);
+ Usuper0 = Unv;
+ Usuper1 = Uv;
+
+ /* Ld = Lsuper0 + Lsuper1 */
+ Ld = cuddBddAndRecur(dd, Cudd_Not(Lsuper0), Cudd_Not(Lsuper1));
+ if (Ld == NULL) {
+ Cudd_RecursiveDeref(dd, Isub0);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub0);
+ Cudd_RecursiveDeref(dd, Isub1);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub1);
+ Cudd_RecursiveDeref(dd, Lsuper0);
+ Cudd_RecursiveDeref(dd, Lsuper1);
+ return(NULL);
+ }
+ Ld = Cudd_Not(Ld);
+ Cudd_Ref(Ld);
+ /* Ud = Usuper0 * Usuper1 */
+ Ud = cuddBddAndRecur(dd, Usuper0, Usuper1);
+ if (Ud == NULL) {
+ Cudd_RecursiveDeref(dd, Isub0);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub0);
+ Cudd_RecursiveDeref(dd, Isub1);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub1);
+ Cudd_RecursiveDeref(dd, Lsuper0);
+ Cudd_RecursiveDeref(dd, Lsuper1);
+ Cudd_RecursiveDeref(dd, Ld);
+ return(NULL);
+ }
+ Cudd_Ref(Ud);
+ Cudd_RecursiveDeref(dd, Lsuper0);
+ Cudd_RecursiveDeref(dd, Lsuper1);
+
+ Id = cuddZddIsop(dd, Ld, Ud, &zdd_Id);
+ if (Id == NULL) {
+ Cudd_RecursiveDeref(dd, Isub0);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub0);
+ Cudd_RecursiveDeref(dd, Isub1);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub1);
+ Cudd_RecursiveDeref(dd, Ld);
+ Cudd_RecursiveDeref(dd, Ud);
+ return(NULL);
+ }
+ /*
+ if ((!cuddIsConstant(Cudd_Regular(Id))) &&
+ (Cudd_Regular(Id)->index != zdd_Id->index / 2 ||
+ dd->permZ[index * 2] > dd->permZ[zdd_Id->index])) {
+ printf("*** ERROR : illegal permutation in ZDD. ***\n");
+ }
+ */
+ Cudd_Ref(Id);
+ Cudd_Ref(zdd_Id);
+ Cudd_RecursiveDeref(dd, Ld);
+ Cudd_RecursiveDeref(dd, Ud);
+
+ x = cuddUniqueInter(dd, index, one, zero);
+ if (x == NULL) {
+ Cudd_RecursiveDeref(dd, Isub0);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub0);
+ Cudd_RecursiveDeref(dd, Isub1);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub1);
+ Cudd_RecursiveDeref(dd, Id);
+ Cudd_RecursiveDerefZdd(dd, zdd_Id);
+ return(NULL);
+ }
+ Cudd_Ref(x);
+ /* term0 = x * Isub0 */
+ term0 = cuddBddAndRecur(dd, Cudd_Not(x), Isub0);
+ if (term0 == NULL) {
+ Cudd_RecursiveDeref(dd, Isub0);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub0);
+ Cudd_RecursiveDeref(dd, Isub1);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub1);
+ Cudd_RecursiveDeref(dd, Id);
+ Cudd_RecursiveDerefZdd(dd, zdd_Id);
+ Cudd_RecursiveDeref(dd, x);
+ return(NULL);
+ }
+ Cudd_Ref(term0);
+ Cudd_RecursiveDeref(dd, Isub0);
+ /* term1 = x * Isub1 */
+ term1 = cuddBddAndRecur(dd, x, Isub1);
+ if (term1 == NULL) {
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub0);
+ Cudd_RecursiveDeref(dd, Isub1);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub1);
+ Cudd_RecursiveDeref(dd, Id);
+ Cudd_RecursiveDerefZdd(dd, zdd_Id);
+ Cudd_RecursiveDeref(dd, x);
+ Cudd_RecursiveDeref(dd, term0);
+ return(NULL);
+ }
+ Cudd_Ref(term1);
+ Cudd_RecursiveDeref(dd, x);
+ Cudd_RecursiveDeref(dd, Isub1);
+ /* sum = term0 + term1 */
+ sum = cuddBddAndRecur(dd, Cudd_Not(term0), Cudd_Not(term1));
+ if (sum == NULL) {
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub0);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub1);
+ Cudd_RecursiveDeref(dd, Id);
+ Cudd_RecursiveDerefZdd(dd, zdd_Id);
+ Cudd_RecursiveDeref(dd, term0);
+ Cudd_RecursiveDeref(dd, term1);
+ return(NULL);
+ }
+ sum = Cudd_Not(sum);
+ Cudd_Ref(sum);
+ Cudd_RecursiveDeref(dd, term0);
+ Cudd_RecursiveDeref(dd, term1);
+ /* r = sum + Id */
+ r = cuddBddAndRecur(dd, Cudd_Not(sum), Cudd_Not(Id));
+ r = Cudd_NotCond(r, r != NULL);
+ if (r == NULL) {
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub0);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub1);
+ Cudd_RecursiveDeref(dd, Id);
+ Cudd_RecursiveDerefZdd(dd, zdd_Id);
+ Cudd_RecursiveDeref(dd, sum);
+ return(NULL);
+ }
+ Cudd_Ref(r);
+ Cudd_RecursiveDeref(dd, sum);
+ Cudd_RecursiveDeref(dd, Id);
+
+ if (zdd_Isub0 != zdd_zero) {
+ z = cuddZddGetNodeIVO(dd, index * 2 + 1, zdd_Isub0, zdd_Id);
+ if (z == NULL) {
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub0);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub1);
+ Cudd_RecursiveDerefZdd(dd, zdd_Id);
+ Cudd_RecursiveDeref(dd, r);
+ return(NULL);
+ }
+ }
+ else {
+ z = zdd_Id;
+ }
+ Cudd_Ref(z);
+ if (zdd_Isub1 != zdd_zero) {
+ y = cuddZddGetNodeIVO(dd, index * 2, zdd_Isub1, z);
+ if (y == NULL) {
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub0);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub1);
+ Cudd_RecursiveDerefZdd(dd, zdd_Id);
+ Cudd_RecursiveDeref(dd, r);
+ Cudd_RecursiveDerefZdd(dd, z);
+ return(NULL);
+ }
+ }
+ else
+ y = z;
+ Cudd_Ref(y);
+
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub0);
+ Cudd_RecursiveDerefZdd(dd, zdd_Isub1);
+ Cudd_RecursiveDerefZdd(dd, zdd_Id);
+ Cudd_RecursiveDerefZdd(dd, z);
+
+ cuddCacheInsert2(dd, cuddBddIsop, L, U, r);
+ cuddCacheInsert2(dd, cacheOp, L, U, y);
+
+ Cudd_Deref(r);
+ Cudd_Deref(y);
+ *zdd_I = y;
+ /*
+ if (Cudd_Regular(r)->index != y->index / 2) {
+ printf("*** ERROR : mismatch in indices between BDD and ZDD. ***\n");
+ }
+ */
+ return(r);
+
+} /* end of cuddZddIsop */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddIsop.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddIsop]
+
+******************************************************************************/
+DdNode *
+cuddBddIsop(
+ DdManager * dd,
+ DdNode * L,
+ DdNode * U)
+{
+ DdNode *one = DD_ONE(dd);
+ DdNode *zero = Cudd_Not(one);
+ int v, top_l, top_u;
+ DdNode *Lsub0, *Usub0, *Lsub1, *Usub1, *Ld, *Ud;
+ DdNode *Lsuper0, *Usuper0, *Lsuper1, *Usuper1;
+ DdNode *Isub0, *Isub1, *Id;
+ DdNode *x;
+ DdNode *term0, *term1, *sum;
+ DdNode *Lv, *Uv, *Lnv, *Unv;
+ DdNode *r;
+ int index;
+
+ statLine(dd);
+ if (L == zero)
+ return(zero);
+ if (U == one)
+ return(one);
+
+ /* Check cache */
+ r = cuddCacheLookup2(dd, cuddBddIsop, L, U);
+ if (r)
+ return(r);
+
+ top_l = dd->perm[Cudd_Regular(L)->index];
+ top_u = dd->perm[Cudd_Regular(U)->index];
+ v = ddMin(top_l, top_u);
+
+ /* Compute cofactors */
+ if (top_l == v) {
+ index = Cudd_Regular(L)->index;
+ Lv = Cudd_T(L);
+ Lnv = Cudd_E(L);
+ if (Cudd_IsComplement(L)) {
+ Lv = Cudd_Not(Lv);
+ Lnv = Cudd_Not(Lnv);
+ }
+ }
+ else {
+ index = Cudd_Regular(U)->index;
+ Lv = Lnv = L;
+ }
+
+ if (top_u == v) {
+ Uv = Cudd_T(U);
+ Unv = Cudd_E(U);
+ if (Cudd_IsComplement(U)) {
+ Uv = Cudd_Not(Uv);
+ Unv = Cudd_Not(Unv);
+ }
+ }
+ else {
+ Uv = Unv = U;
+ }
+
+ Lsub0 = cuddBddAndRecur(dd, Lnv, Cudd_Not(Uv));
+ if (Lsub0 == NULL)
+ return(NULL);
+ Cudd_Ref(Lsub0);
+ Usub0 = Unv;
+ Lsub1 = cuddBddAndRecur(dd, Lv, Cudd_Not(Unv));
+ if (Lsub1 == NULL) {
+ Cudd_RecursiveDeref(dd, Lsub0);
+ return(NULL);
+ }
+ Cudd_Ref(Lsub1);
+ Usub1 = Uv;
+
+ Isub0 = cuddBddIsop(dd, Lsub0, Usub0);
+ if (Isub0 == NULL) {
+ Cudd_RecursiveDeref(dd, Lsub0);
+ Cudd_RecursiveDeref(dd, Lsub1);
+ return(NULL);
+ }
+ Cudd_Ref(Isub0);
+ Isub1 = cuddBddIsop(dd, Lsub1, Usub1);
+ if (Isub1 == NULL) {
+ Cudd_RecursiveDeref(dd, Lsub0);
+ Cudd_RecursiveDeref(dd, Lsub1);
+ Cudd_RecursiveDeref(dd, Isub0);
+ return(NULL);
+ }
+ Cudd_Ref(Isub1);
+ Cudd_RecursiveDeref(dd, Lsub0);
+ Cudd_RecursiveDeref(dd, Lsub1);
+
+ Lsuper0 = cuddBddAndRecur(dd, Lnv, Cudd_Not(Isub0));
+ if (Lsuper0 == NULL) {
+ Cudd_RecursiveDeref(dd, Isub0);
+ Cudd_RecursiveDeref(dd, Isub1);
+ return(NULL);
+ }
+ Cudd_Ref(Lsuper0);
+ Lsuper1 = cuddBddAndRecur(dd, Lv, Cudd_Not(Isub1));
+ if (Lsuper1 == NULL) {
+ Cudd_RecursiveDeref(dd, Isub0);
+ Cudd_RecursiveDeref(dd, Isub1);
+ Cudd_RecursiveDeref(dd, Lsuper0);
+ return(NULL);
+ }
+ Cudd_Ref(Lsuper1);
+ Usuper0 = Unv;
+ Usuper1 = Uv;
+
+ /* Ld = Lsuper0 + Lsuper1 */
+ Ld = cuddBddAndRecur(dd, Cudd_Not(Lsuper0), Cudd_Not(Lsuper1));
+ Ld = Cudd_NotCond(Ld, Ld != NULL);
+ if (Ld == NULL) {
+ Cudd_RecursiveDeref(dd, Isub0);
+ Cudd_RecursiveDeref(dd, Isub1);
+ Cudd_RecursiveDeref(dd, Lsuper0);
+ Cudd_RecursiveDeref(dd, Lsuper1);
+ return(NULL);
+ }
+ Cudd_Ref(Ld);
+ Ud = cuddBddAndRecur(dd, Usuper0, Usuper1);
+ if (Ud == NULL) {
+ Cudd_RecursiveDeref(dd, Isub0);
+ Cudd_RecursiveDeref(dd, Isub1);
+ Cudd_RecursiveDeref(dd, Lsuper0);
+ Cudd_RecursiveDeref(dd, Lsuper1);
+ Cudd_RecursiveDeref(dd, Ld);
+ return(NULL);
+ }
+ Cudd_Ref(Ud);
+ Cudd_RecursiveDeref(dd, Lsuper0);
+ Cudd_RecursiveDeref(dd, Lsuper1);
+
+ Id = cuddBddIsop(dd, Ld, Ud);
+ if (Id == NULL) {
+ Cudd_RecursiveDeref(dd, Isub0);
+ Cudd_RecursiveDeref(dd, Isub1);
+ Cudd_RecursiveDeref(dd, Ld);
+ Cudd_RecursiveDeref(dd, Ud);
+ return(NULL);
+ }
+ Cudd_Ref(Id);
+ Cudd_RecursiveDeref(dd, Ld);
+ Cudd_RecursiveDeref(dd, Ud);
+
+ x = cuddUniqueInter(dd, index, one, zero);
+ if (x == NULL) {
+ Cudd_RecursiveDeref(dd, Isub0);
+ Cudd_RecursiveDeref(dd, Isub1);
+ Cudd_RecursiveDeref(dd, Id);
+ return(NULL);
+ }
+ Cudd_Ref(x);
+ term0 = cuddBddAndRecur(dd, Cudd_Not(x), Isub0);
+ if (term0 == NULL) {
+ Cudd_RecursiveDeref(dd, Isub0);
+ Cudd_RecursiveDeref(dd, Isub1);
+ Cudd_RecursiveDeref(dd, Id);
+ Cudd_RecursiveDeref(dd, x);
+ return(NULL);
+ }
+ Cudd_Ref(term0);
+ Cudd_RecursiveDeref(dd, Isub0);
+ term1 = cuddBddAndRecur(dd, x, Isub1);
+ if (term1 == NULL) {
+ Cudd_RecursiveDeref(dd, Isub1);
+ Cudd_RecursiveDeref(dd, Id);
+ Cudd_RecursiveDeref(dd, x);
+ Cudd_RecursiveDeref(dd, term0);
+ return(NULL);
+ }
+ Cudd_Ref(term1);
+ Cudd_RecursiveDeref(dd, x);
+ Cudd_RecursiveDeref(dd, Isub1);
+ /* sum = term0 + term1 */
+ sum = cuddBddAndRecur(dd, Cudd_Not(term0), Cudd_Not(term1));
+ sum = Cudd_NotCond(sum, sum != NULL);
+ if (sum == NULL) {
+ Cudd_RecursiveDeref(dd, Id);
+ Cudd_RecursiveDeref(dd, term0);
+ Cudd_RecursiveDeref(dd, term1);
+ return(NULL);
+ }
+ Cudd_Ref(sum);
+ Cudd_RecursiveDeref(dd, term0);
+ Cudd_RecursiveDeref(dd, term1);
+ /* r = sum + Id */
+ r = cuddBddAndRecur(dd, Cudd_Not(sum), Cudd_Not(Id));
+ r = Cudd_NotCond(r, r != NULL);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd, Id);
+ Cudd_RecursiveDeref(dd, sum);
+ return(NULL);
+ }
+ Cudd_Ref(r);
+ Cudd_RecursiveDeref(dd, sum);
+ Cudd_RecursiveDeref(dd, Id);
+
+ cuddCacheInsert2(dd, cuddBddIsop, L, U, r);
+
+ Cudd_Deref(r);
+ return(r);
+
+} /* end of cuddBddIsop */
+
+
+/**Function********************************************************************
+
+ Synopsis [Converts a ZDD cover to a BDD graph.]
+
+ Description [Converts a ZDD cover to a BDD graph. If successful, it
+ returns a BDD node, otherwise it returns NULL. It is a recursive
+ algorithm as the following. First computes 3 cofactors of a ZDD cover;
+ f1, f0 and fd. Second, compute BDDs(b1, b0 and bd) of f1, f0 and fd.
+ Third, compute T=b1+bd and E=b0+bd. Fourth, compute ITE(v,T,E) where v
+ is the variable which has the index of the top node of the ZDD cover.
+ In this case, since the index of v can be larger than either one of T or
+ one of E, cuddUniqueInterIVO is called, here IVO stands for
+ independent variable ordering.]
+
+ SideEffects []
+
+ SeeAlso [Cudd_MakeBddFromZddCover]
+
+******************************************************************************/
+DdNode *
+cuddMakeBddFromZddCover(
+ DdManager * dd,
+ DdNode * node)
+{
+ DdNode *neW;
+ int v;
+ DdNode *f1, *f0, *fd;
+ DdNode *b1, *b0, *bd;
+ DdNode *T, *E;
+
+ statLine(dd);
+ if (node == dd->one)
+ return(dd->one);
+ if (node == dd->zero)
+ return(Cudd_Not(dd->one));
+
+ /* Check cache */
+ neW = cuddCacheLookup1(dd, cuddMakeBddFromZddCover, node);
+ if (neW)
+ return(neW);
+
+ v = Cudd_Regular(node)->index; /* either yi or zi */
+ cuddZddGetCofactors3(dd, node, v, &f1, &f0, &fd);
+ Cudd_Ref(f1);
+ Cudd_Ref(f0);
+ Cudd_Ref(fd);
+
+ b1 = cuddMakeBddFromZddCover(dd, f1);
+ if (!b1) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ return(NULL);
+ }
+ Cudd_Ref(b1);
+ b0 = cuddMakeBddFromZddCover(dd, f0);
+ if (!b1) {
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDeref(dd, b1);
+ return(NULL);
+ }
+ Cudd_Ref(b0);
+ Cudd_RecursiveDerefZdd(dd, f1);
+ Cudd_RecursiveDerefZdd(dd, f0);
+ if (fd != dd->zero) {
+ bd = cuddMakeBddFromZddCover(dd, fd);
+ if (!bd) {
+ Cudd_RecursiveDerefZdd(dd, fd);
+ Cudd_RecursiveDeref(dd, b1);
+ Cudd_RecursiveDeref(dd, b0);
+ return(NULL);
+ }
+ Cudd_Ref(bd);
+ Cudd_RecursiveDerefZdd(dd, fd);
+
+ T = cuddBddAndRecur(dd, Cudd_Not(b1), Cudd_Not(bd));
+ if (!T) {
+ Cudd_RecursiveDeref(dd, b1);
+ Cudd_RecursiveDeref(dd, b0);
+ Cudd_RecursiveDeref(dd, bd);
+ return(NULL);
+ }
+ T = Cudd_NotCond(T, T != NULL);
+ Cudd_Ref(T);
+ Cudd_RecursiveDeref(dd, b1);
+ E = cuddBddAndRecur(dd, Cudd_Not(b0), Cudd_Not(bd));
+ if (!E) {
+ Cudd_RecursiveDeref(dd, b0);
+ Cudd_RecursiveDeref(dd, bd);
+ Cudd_RecursiveDeref(dd, T);
+ return(NULL);
+ }
+ E = Cudd_NotCond(E, E != NULL);
+ Cudd_Ref(E);
+ Cudd_RecursiveDeref(dd, b0);
+ Cudd_RecursiveDeref(dd, bd);
+ }
+ else {
+ Cudd_RecursiveDerefZdd(dd, fd);
+ T = b1;
+ E = b0;
+ }
+
+ if (Cudd_IsComplement(T)) {
+ neW = cuddUniqueInterIVO(dd, v / 2, Cudd_Not(T), Cudd_Not(E));
+ if (!neW) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ neW = Cudd_Not(neW);
+ }
+ else {
+ neW = cuddUniqueInterIVO(dd, v / 2, T, E);
+ if (!neW) {
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+ return(NULL);
+ }
+ }
+ Cudd_Ref(neW);
+ Cudd_RecursiveDeref(dd, T);
+ Cudd_RecursiveDeref(dd, E);
+
+ cuddCacheInsert1(dd, cuddMakeBddFromZddCover, node, neW);
+ Cudd_Deref(neW);
+ return(neW);
+
+} /* end of cuddMakeBddFromZddCover */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
diff --git a/src/bdd/cudd/cuddZddLin.c b/src/bdd/cudd/cuddZddLin.c
new file mode 100644
index 00000000..9369bb05
--- /dev/null
+++ b/src/bdd/cudd/cuddZddLin.c
@@ -0,0 +1,939 @@
+/**CFile***********************************************************************
+
+ FileName [cuddZddLin.c]
+
+ PackageName [cudd]
+
+ Synopsis [Procedures for dynamic variable ordering of ZDDs.]
+
+ Description [Internal procedures included in this module:
+ <ul>
+ <li> cuddZddLinearSifting()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> cuddZddLinearInPlace()
+ <li> cuddZddLinerAux()
+ <li> cuddZddLinearUp()
+ <li> cuddZddLinearDown()
+ <li> cuddZddLinearBackward()
+ <li> cuddZddUndoMoves()
+ </ul>
+ ]
+
+ SeeAlso [cuddLinear.c cuddZddReord.c]
+
+ Author [Fabio Somenzi]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define CUDD_SWAP_MOVE 0
+#define CUDD_LINEAR_TRANSFORM_MOVE 1
+#define CUDD_INVERSE_TRANSFORM_MOVE 2
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddZddLin.c,v 1.1.1.1 2003/02/24 22:23:54 wjiang Exp $";
+#endif
+
+extern int *zdd_entry;
+extern int zddTotalNumberSwapping;
+static int zddTotalNumberLinearTr;
+static DdNode *empty;
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int cuddZddLinearAux ARGS((DdManager *table, int x, int xLow, int xHigh));
+static Move * cuddZddLinearUp ARGS((DdManager *table, int y, int xLow, Move *prevMoves));
+static Move * cuddZddLinearDown ARGS((DdManager *table, int x, int xHigh, Move *prevMoves));
+static int cuddZddLinearBackward ARGS((DdManager *table, int size, Move *moves));
+static Move* cuddZddUndoMoves ARGS((DdManager *table, Move *moves));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+
+
+/**Function********************************************************************
+
+ Synopsis [Implementation of the linear sifting algorithm for ZDDs.]
+
+ Description [Implementation of the linear sifting algorithm for ZDDs.
+ Assumes that no dead nodes are present.
+ <ol>
+ <li> Order all the variables according to the number of entries
+ in each unique table.
+ <li> Sift the variable up and down and applies the XOR transformation,
+ remembering each time the total size of the DD heap.
+ <li> Select the best permutation.
+ <li> Repeat 3 and 4 for all variables.
+ </ol>
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddZddLinearSifting(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int i;
+ int *var;
+ int size;
+ int x;
+ int result;
+#ifdef DD_STATS
+ int previousSize;
+#endif
+
+ size = table->sizeZ;
+ empty = table->zero;
+
+ /* Find order in which to sift variables. */
+ var = NULL;
+ zdd_entry = ALLOC(int, size);
+ if (zdd_entry == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto cuddZddSiftingOutOfMem;
+ }
+ var = ALLOC(int, size);
+ if (var == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto cuddZddSiftingOutOfMem;
+ }
+
+ for (i = 0; i < size; i++) {
+ x = table->permZ[i];
+ zdd_entry[i] = table->subtableZ[x].keys;
+ var[i] = i;
+ }
+
+ qsort((void *)var, size, sizeof(int), (int (*)(const void *, const void *))cuddZddUniqueCompare);
+
+ /* Now sift. */
+ for (i = 0; i < ddMin(table->siftMaxVar, size); i++) {
+ if (zddTotalNumberSwapping >= table->siftMaxSwap)
+ break;
+ x = table->permZ[var[i]];
+ if (x < lower || x > upper) continue;
+#ifdef DD_STATS
+ previousSize = table->keysZ;
+#endif
+ result = cuddZddLinearAux(table, x, lower, upper);
+ if (!result)
+ goto cuddZddSiftingOutOfMem;
+#ifdef DD_STATS
+ if (table->keysZ < (unsigned) previousSize) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keysZ > (unsigned) previousSize) {
+ (void) fprintf(table->out,"+"); /* should never happen */
+ (void) fprintf(table->out,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keysZ , var[i]);
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+
+ FREE(var);
+ FREE(zdd_entry);
+
+ return(1);
+
+cuddZddSiftingOutOfMem:
+
+ if (zdd_entry != NULL) FREE(zdd_entry);
+ if (var != NULL) FREE(var);
+
+ return(0);
+
+} /* end of cuddZddLinearSifting */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Linearly combines two adjacent variables.]
+
+ Description [Linearly combines two adjacent variables. It assumes
+ that no dead nodes are present on entry to this procedure. The
+ procedure then guarantees that no dead nodes will be present when it
+ terminates. cuddZddLinearInPlace assumes that x &lt; y. Returns the
+ number of keys in the table if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddZddSwapInPlace cuddLinearInPlace]
+
+******************************************************************************/
+int
+cuddZddLinearInPlace(
+ DdManager * table,
+ int x,
+ int y)
+{
+ DdNodePtr *xlist, *ylist;
+ int xindex, yindex;
+ int xslots, yslots;
+ int xshift, yshift;
+ int oldxkeys, oldykeys;
+ int newxkeys, newykeys;
+ int i;
+ int posn;
+ DdNode *f, *f1, *f0, *f11, *f10, *f01, *f00;
+ DdNode *newf1, *newf0, *g, *next, *previous;
+ DdNode *special;
+
+#ifdef DD_DEBUG
+ assert(x < y);
+ assert(cuddZddNextHigh(table,x) == y);
+ assert(table->subtableZ[x].keys != 0);
+ assert(table->subtableZ[y].keys != 0);
+ assert(table->subtableZ[x].dead == 0);
+ assert(table->subtableZ[y].dead == 0);
+#endif
+
+ zddTotalNumberLinearTr++;
+
+ /* Get parameters of x subtable. */
+ xindex = table->invpermZ[x];
+ xlist = table->subtableZ[x].nodelist;
+ oldxkeys = table->subtableZ[x].keys;
+ xslots = table->subtableZ[x].slots;
+ xshift = table->subtableZ[x].shift;
+ newxkeys = 0;
+
+ /* Get parameters of y subtable. */
+ yindex = table->invpermZ[y];
+ ylist = table->subtableZ[y].nodelist;
+ oldykeys = table->subtableZ[y].keys;
+ yslots = table->subtableZ[y].slots;
+ yshift = table->subtableZ[y].shift;
+ newykeys = oldykeys;
+
+ /* The nodes in the x layer are put in two chains. The chain
+ ** pointed by g holds the normal nodes. When re-expressed they stay
+ ** in the x list. The chain pointed by special holds the elements
+ ** that will move to the y list.
+ */
+ g = special = NULL;
+ for (i = 0; i < xslots; i++) {
+ f = xlist[i];
+ if (f == NULL) continue;
+ xlist[i] = NULL;
+ while (f != NULL) {
+ next = f->next;
+ f1 = cuddT(f);
+ /* if (f1->index == yindex) */ cuddSatDec(f1->ref);
+ f0 = cuddE(f);
+ /* if (f0->index == yindex) */ cuddSatDec(f0->ref);
+ if ((int) f1->index == yindex && cuddE(f1) == empty &&
+ (int) f0->index != yindex) {
+ f->next = special;
+ special = f;
+ } else {
+ f->next = g;
+ g = f;
+ }
+ f = next;
+ } /* while there are elements in the collision chain */
+ } /* for each slot of the x subtable */
+
+ /* Mark y nodes with pointers from above x. We mark them by
+ ** changing their index to x.
+ */
+ for (i = 0; i < yslots; i++) {
+ f = ylist[i];
+ while (f != NULL) {
+ if (f->ref != 0) {
+ f->index = xindex;
+ }
+ f = f->next;
+ } /* while there are elements in the collision chain */
+ } /* for each slot of the y subtable */
+
+ /* Move special nodes to the y list. */
+ f = special;
+ while (f != NULL) {
+ next = f->next;
+ f1 = cuddT(f);
+ f11 = cuddT(f1);
+ cuddT(f) = f11;
+ cuddSatInc(f11->ref);
+ f0 = cuddE(f);
+ cuddSatInc(f0->ref);
+ f->index = yindex;
+ /* Insert at the beginning of the list so that it will be
+ ** found first if there is a duplicate. The duplicate will
+ ** eventually be moved or garbage collected. No node
+ ** re-expression will add a pointer to it.
+ */
+ posn = ddHash(f11, f0, yshift);
+ f->next = ylist[posn];
+ ylist[posn] = f;
+ newykeys++;
+ f = next;
+ }
+
+ /* Take care of the remaining x nodes that must be re-expressed.
+ ** They form a linked list pointed by g.
+ */
+ f = g;
+ while (f != NULL) {
+#ifdef DD_COUNT
+ table->swapSteps++;
+#endif
+ next = f->next;
+ /* Find f1, f0, f11, f10, f01, f00. */
+ f1 = cuddT(f);
+ if ((int) f1->index == yindex || (int) f1->index == xindex) {
+ f11 = cuddT(f1); f10 = cuddE(f1);
+ } else {
+ f11 = empty; f10 = f1;
+ }
+ f0 = cuddE(f);
+ if ((int) f0->index == yindex || (int) f0->index == xindex) {
+ f01 = cuddT(f0); f00 = cuddE(f0);
+ } else {
+ f01 = empty; f00 = f0;
+ }
+ /* Create the new T child. */
+ if (f01 == empty) {
+ newf1 = f10;
+ cuddSatInc(newf1->ref);
+ } else {
+ /* Check ylist for triple (yindex, f01, f10). */
+ posn = ddHash(f01, f10, yshift);
+ /* For each element newf1 in collision list ylist[posn]. */
+ newf1 = ylist[posn];
+ /* Search the collision chain skipping the marked nodes. */
+ while (newf1 != NULL) {
+ if (cuddT(newf1) == f01 && cuddE(newf1) == f10 &&
+ (int) newf1->index == yindex) {
+ cuddSatInc(newf1->ref);
+ break; /* match */
+ }
+ newf1 = newf1->next;
+ } /* while newf1 */
+ if (newf1 == NULL) { /* no match */
+ newf1 = cuddDynamicAllocNode(table);
+ if (newf1 == NULL)
+ goto zddSwapOutOfMem;
+ newf1->index = yindex; newf1->ref = 1;
+ cuddT(newf1) = f01;
+ cuddE(newf1) = f10;
+ /* Insert newf1 in the collision list ylist[pos];
+ ** increase the ref counts of f01 and f10
+ */
+ newykeys++;
+ newf1->next = ylist[posn];
+ ylist[posn] = newf1;
+ cuddSatInc(f01->ref);
+ cuddSatInc(f10->ref);
+ }
+ }
+ cuddT(f) = newf1;
+
+ /* Do the same for f0. */
+ /* Create the new E child. */
+ if (f11 == empty) {
+ newf0 = f00;
+ cuddSatInc(newf0->ref);
+ } else {
+ /* Check ylist for triple (yindex, f11, f00). */
+ posn = ddHash(f11, f00, yshift);
+ /* For each element newf0 in collision list ylist[posn]. */
+ newf0 = ylist[posn];
+ while (newf0 != NULL) {
+ if (cuddT(newf0) == f11 && cuddE(newf0) == f00 &&
+ (int) newf0->index == yindex) {
+ cuddSatInc(newf0->ref);
+ break; /* match */
+ }
+ newf0 = newf0->next;
+ } /* while newf0 */
+ if (newf0 == NULL) { /* no match */
+ newf0 = cuddDynamicAllocNode(table);
+ if (newf0 == NULL)
+ goto zddSwapOutOfMem;
+ newf0->index = yindex; newf0->ref = 1;
+ cuddT(newf0) = f11; cuddE(newf0) = f00;
+ /* Insert newf0 in the collision list ylist[posn];
+ ** increase the ref counts of f11 and f00.
+ */
+ newykeys++;
+ newf0->next = ylist[posn];
+ ylist[posn] = newf0;
+ cuddSatInc(f11->ref);
+ cuddSatInc(f00->ref);
+ }
+ }
+ cuddE(f) = newf0;
+
+ /* Re-insert the modified f in xlist.
+ ** The modified f does not already exists in xlist.
+ ** (Because of the uniqueness of the cofactors.)
+ */
+ posn = ddHash(newf1, newf0, xshift);
+ newxkeys++;
+ f->next = xlist[posn];
+ xlist[posn] = f;
+ f = next;
+ } /* while f != NULL */
+
+ /* GC the y layer and move the marked nodes to the x list. */
+
+ /* For each node f in ylist. */
+ for (i = 0; i < yslots; i++) {
+ previous = NULL;
+ f = ylist[i];
+ while (f != NULL) {
+ next = f->next;
+ if (f->ref == 0) {
+ cuddSatDec(cuddT(f)->ref);
+ cuddSatDec(cuddE(f)->ref);
+ cuddDeallocNode(table, f);
+ newykeys--;
+ if (previous == NULL)
+ ylist[i] = next;
+ else
+ previous->next = next;
+ } else if ((int) f->index == xindex) { /* move marked node */
+ if (previous == NULL)
+ ylist[i] = next;
+ else
+ previous->next = next;
+ f1 = cuddT(f);
+ cuddSatDec(f1->ref);
+ /* Check ylist for triple (yindex, f1, empty). */
+ posn = ddHash(f1, empty, yshift);
+ /* For each element newf1 in collision list ylist[posn]. */
+ newf1 = ylist[posn];
+ while (newf1 != NULL) {
+ if (cuddT(newf1) == f1 && cuddE(newf1) == empty &&
+ (int) newf1->index == yindex) {
+ cuddSatInc(newf1->ref);
+ break; /* match */
+ }
+ newf1 = newf1->next;
+ } /* while newf1 */
+ if (newf1 == NULL) { /* no match */
+ newf1 = cuddDynamicAllocNode(table);
+ if (newf1 == NULL)
+ goto zddSwapOutOfMem;
+ newf1->index = yindex; newf1->ref = 1;
+ cuddT(newf1) = f1; cuddE(newf1) = empty;
+ /* Insert newf1 in the collision list ylist[posn];
+ ** increase the ref counts of f1 and empty.
+ */
+ newykeys++;
+ newf1->next = ylist[posn];
+ ylist[posn] = newf1;
+ if (posn == i && previous == NULL)
+ previous = newf1;
+ cuddSatInc(f1->ref);
+ cuddSatInc(empty->ref);
+ }
+ cuddT(f) = newf1;
+ f0 = cuddE(f);
+ /* Insert f in x list. */
+ posn = ddHash(newf1, f0, xshift);
+ newxkeys++;
+ newykeys--;
+ f->next = xlist[posn];
+ xlist[posn] = f;
+ } else {
+ previous = f;
+ }
+ f = next;
+ } /* while f */
+ } /* for i */
+
+ /* Set the appropriate fields in table. */
+ table->subtableZ[x].keys = newxkeys;
+ table->subtableZ[y].keys = newykeys;
+
+ table->keysZ += newxkeys + newykeys - oldxkeys - oldykeys;
+
+ /* Update univ section; univ[x] remains the same. */
+ table->univ[y] = cuddT(table->univ[x]);
+
+#if 0
+ (void) fprintf(table->out,"x = %d y = %d\n", x, y);
+ (void) Cudd_DebugCheck(table);
+ (void) Cudd_CheckKeys(table);
+#endif
+
+ return (table->keysZ);
+
+zddSwapOutOfMem:
+ (void) fprintf(table->err, "Error: cuddZddSwapInPlace out of memory\n");
+
+ return (0);
+
+} /* end of cuddZddLinearInPlace */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given xLow <= x <= xHigh moves x up and down between the
+ boundaries.]
+
+ Description [Given xLow <= x <= xHigh moves x up and down between the
+ boundaries. Finds the best position and does the required changes.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddZddLinearAux(
+ DdManager * table,
+ int x,
+ int xLow,
+ int xHigh)
+{
+ Move *move;
+ Move *moveUp; /* list of up move */
+ Move *moveDown; /* list of down move */
+
+ int initial_size;
+ int result;
+
+ initial_size = table->keysZ;
+
+#ifdef DD_DEBUG
+ assert(table->subtableZ[x].keys > 0);
+#endif
+
+ moveDown = NULL;
+ moveUp = NULL;
+
+ if (x == xLow) {
+ moveDown = cuddZddLinearDown(table, x, xHigh, NULL);
+ /* At this point x --> xHigh. */
+ if (moveDown == (Move *) CUDD_OUT_OF_MEM)
+ goto cuddZddLinearAuxOutOfMem;
+ /* Move backward and stop at best position. */
+ result = cuddZddLinearBackward(table, initial_size, moveDown);
+ if (!result)
+ goto cuddZddLinearAuxOutOfMem;
+
+ } else if (x == xHigh) {
+ moveUp = cuddZddLinearUp(table, x, xLow, NULL);
+ /* At this point x --> xLow. */
+ if (moveUp == (Move *) CUDD_OUT_OF_MEM)
+ goto cuddZddLinearAuxOutOfMem;
+ /* Move backward and stop at best position. */
+ result = cuddZddLinearBackward(table, initial_size, moveUp);
+ if (!result)
+ goto cuddZddLinearAuxOutOfMem;
+
+ } else if ((x - xLow) > (xHigh - x)) { /* must go down first: shorter */
+ moveDown = cuddZddLinearDown(table, x, xHigh, NULL);
+ /* At this point x --> xHigh. */
+ if (moveDown == (Move *) CUDD_OUT_OF_MEM)
+ goto cuddZddLinearAuxOutOfMem;
+ moveUp = cuddZddUndoMoves(table,moveDown);
+#ifdef DD_DEBUG
+ assert(moveUp == NULL || moveUp->x == x);
+#endif
+ moveUp = cuddZddLinearUp(table, x, xLow, moveUp);
+ if (moveUp == (Move *) CUDD_OUT_OF_MEM)
+ goto cuddZddLinearAuxOutOfMem;
+ /* Move backward and stop at best position. */
+ result = cuddZddLinearBackward(table, initial_size, moveUp);
+ if (!result)
+ goto cuddZddLinearAuxOutOfMem;
+
+ } else {
+ moveUp = cuddZddLinearUp(table, x, xLow, NULL);
+ /* At this point x --> xHigh. */
+ if (moveUp == (Move *) CUDD_OUT_OF_MEM)
+ goto cuddZddLinearAuxOutOfMem;
+ /* Then move up. */
+ moveDown = cuddZddUndoMoves(table,moveUp);
+#ifdef DD_DEBUG
+ assert(moveDown == NULL || moveDown->y == x);
+#endif
+ moveDown = cuddZddLinearDown(table, x, xHigh, moveDown);
+ if (moveDown == (Move *) CUDD_OUT_OF_MEM)
+ goto cuddZddLinearAuxOutOfMem;
+ /* Move backward and stop at best position. */
+ result = cuddZddLinearBackward(table, initial_size, moveDown);
+ if (!result)
+ goto cuddZddLinearAuxOutOfMem;
+ }
+
+ while (moveDown != NULL) {
+ move = moveDown->next;
+ cuddDeallocNode(table, (DdNode *)moveDown);
+ moveDown = move;
+ }
+ while (moveUp != NULL) {
+ move = moveUp->next;
+ cuddDeallocNode(table, (DdNode *)moveUp);
+ moveUp = move;
+ }
+
+ return(1);
+
+cuddZddLinearAuxOutOfMem:
+ if (moveDown != (Move *) CUDD_OUT_OF_MEM) {
+ while (moveDown != NULL) {
+ move = moveDown->next;
+ cuddDeallocNode(table, (DdNode *)moveDown);
+ moveDown = move;
+ }
+ }
+ if (moveUp != (Move *) CUDD_OUT_OF_MEM) {
+ while (moveUp != NULL) {
+ move = moveUp->next;
+ cuddDeallocNode(table, (DdNode *)moveUp);
+ moveUp = move;
+ }
+ }
+
+ return(0);
+
+} /* end of cuddZddLinearAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts a variable up applying the XOR transformation.]
+
+ Description [Sifts a variable up applying the XOR
+ transformation. Moves y up until either it reaches the bound (xLow)
+ or the size of the ZDD heap increases too much. Returns the set of
+ moves in case of success; NULL if memory is full.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static Move *
+cuddZddLinearUp(
+ DdManager * table,
+ int y,
+ int xLow,
+ Move * prevMoves)
+{
+ Move *moves;
+ Move *move;
+ int x;
+ int size, newsize;
+ int limitSize;
+
+ moves = prevMoves;
+ limitSize = table->keysZ;
+
+ x = cuddZddNextLow(table, y);
+ while (x >= xLow) {
+ size = cuddZddSwapInPlace(table, x, y);
+ if (size == 0)
+ goto cuddZddLinearUpOutOfMem;
+ newsize = cuddZddLinearInPlace(table, x, y);
+ if (newsize == 0)
+ goto cuddZddLinearUpOutOfMem;
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto cuddZddLinearUpOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->next = moves;
+ moves = move;
+ move->flags = CUDD_SWAP_MOVE;
+ if (newsize > size) {
+ /* Undo transformation. The transformation we apply is
+ ** its own inverse. Hence, we just apply the transformation
+ ** again.
+ */
+ newsize = cuddZddLinearInPlace(table,x,y);
+ if (newsize == 0) goto cuddZddLinearUpOutOfMem;
+#ifdef DD_DEBUG
+ if (newsize != size) {
+ (void) fprintf(table->err,"Change in size after identity transformation! From %d to %d\n",size,newsize);
+ }
+#endif
+ } else {
+ size = newsize;
+ move->flags = CUDD_LINEAR_TRANSFORM_MOVE;
+ }
+ move->size = size;
+
+ if ((double)size > (double)limitSize * table->maxGrowth)
+ break;
+ if (size < limitSize)
+ limitSize = size;
+
+ y = x;
+ x = cuddZddNextLow(table, y);
+ }
+ return(moves);
+
+cuddZddLinearUpOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *)moves);
+ moves = move;
+ }
+ return((Move *) CUDD_OUT_OF_MEM);
+
+} /* end of cuddZddLinearUp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts a variable down and applies the XOR transformation.]
+
+ Description [Sifts a variable down. Moves x down until either it
+ reaches the bound (xHigh) or the size of the ZDD heap increases too
+ much. Returns the set of moves in case of success; NULL if memory is
+ full.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static Move *
+cuddZddLinearDown(
+ DdManager * table,
+ int x,
+ int xHigh,
+ Move * prevMoves)
+{
+ Move *moves;
+ Move *move;
+ int y;
+ int size, newsize;
+ int limitSize;
+
+ moves = prevMoves;
+ limitSize = table->keysZ;
+
+ y = cuddZddNextHigh(table, x);
+ while (y <= xHigh) {
+ size = cuddZddSwapInPlace(table, x, y);
+ if (size == 0)
+ goto cuddZddLinearDownOutOfMem;
+ newsize = cuddZddLinearInPlace(table, x, y);
+ if (newsize == 0)
+ goto cuddZddLinearDownOutOfMem;
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto cuddZddLinearDownOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->next = moves;
+ moves = move;
+ move->flags = CUDD_SWAP_MOVE;
+ if (newsize > size) {
+ /* Undo transformation. The transformation we apply is
+ ** its own inverse. Hence, we just apply the transformation
+ ** again.
+ */
+ newsize = cuddZddLinearInPlace(table,x,y);
+ if (newsize == 0) goto cuddZddLinearDownOutOfMem;
+ if (newsize != size) {
+ (void) fprintf(table->err,"Change in size after identity transformation! From %d to %d\n",size,newsize);
+ }
+ } else {
+ size = newsize;
+ move->flags = CUDD_LINEAR_TRANSFORM_MOVE;
+ }
+ move->size = size;
+
+ if ((double)size > (double)limitSize * table->maxGrowth)
+ break;
+ if (size < limitSize)
+ limitSize = size;
+
+ x = y;
+ y = cuddZddNextHigh(table, x);
+ }
+ return(moves);
+
+cuddZddLinearDownOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *)moves);
+ moves = move;
+ }
+ return((Move *) CUDD_OUT_OF_MEM);
+
+} /* end of cuddZddLinearDown */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given a set of moves, returns the ZDD heap to the position
+ giving the minimum size.]
+
+ Description [Given a set of moves, returns the ZDD heap to the
+ position giving the minimum size. In case of ties, returns to the
+ closest position giving the minimum size. Returns 1 in case of
+ success; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddZddLinearBackward(
+ DdManager * table,
+ int size,
+ Move * moves)
+{
+ Move *move;
+ int res;
+
+ /* Find the minimum size among moves. */
+ for (move = moves; move != NULL; move = move->next) {
+ if (move->size < size) {
+ size = move->size;
+ }
+ }
+
+ for (move = moves; move != NULL; move = move->next) {
+ if (move->size == size) return(1);
+ if (move->flags == CUDD_LINEAR_TRANSFORM_MOVE) {
+ res = cuddZddLinearInPlace(table,(int)move->x,(int)move->y);
+ if (!res) return(0);
+ }
+ res = cuddZddSwapInPlace(table, move->x, move->y);
+ if (!res)
+ return(0);
+ if (move->flags == CUDD_INVERSE_TRANSFORM_MOVE) {
+ res = cuddZddLinearInPlace(table,(int)move->x,(int)move->y);
+ if (!res) return(0);
+ }
+ }
+
+ return(1);
+
+} /* end of cuddZddLinearBackward */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given a set of moves, returns the ZDD heap to the order
+ in effect before the moves.]
+
+ Description [Given a set of moves, returns the ZDD heap to the
+ order in effect before the moves. Returns 1 in case of success;
+ 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static Move*
+cuddZddUndoMoves(
+ DdManager * table,
+ Move * moves)
+{
+ Move *invmoves = NULL;
+ Move *move;
+ Move *invmove;
+ int size;
+
+ for (move = moves; move != NULL; move = move->next) {
+ invmove = (Move *) cuddDynamicAllocNode(table);
+ if (invmove == NULL) goto cuddZddUndoMovesOutOfMem;
+ invmove->x = move->x;
+ invmove->y = move->y;
+ invmove->next = invmoves;
+ invmoves = invmove;
+ if (move->flags == CUDD_SWAP_MOVE) {
+ invmove->flags = CUDD_SWAP_MOVE;
+ size = cuddZddSwapInPlace(table,(int)move->x,(int)move->y);
+ if (!size) goto cuddZddUndoMovesOutOfMem;
+ } else if (move->flags == CUDD_LINEAR_TRANSFORM_MOVE) {
+ invmove->flags = CUDD_INVERSE_TRANSFORM_MOVE;
+ size = cuddZddLinearInPlace(table,(int)move->x,(int)move->y);
+ if (!size) goto cuddZddUndoMovesOutOfMem;
+ size = cuddZddSwapInPlace(table,(int)move->x,(int)move->y);
+ if (!size) goto cuddZddUndoMovesOutOfMem;
+ } else { /* must be CUDD_INVERSE_TRANSFORM_MOVE */
+#ifdef DD_DEBUG
+ (void) fprintf(table->err,"Unforseen event in ddUndoMoves!\n");
+#endif
+ invmove->flags = CUDD_LINEAR_TRANSFORM_MOVE;
+ size = cuddZddSwapInPlace(table,(int)move->x,(int)move->y);
+ if (!size) goto cuddZddUndoMovesOutOfMem;
+ size = cuddZddLinearInPlace(table,(int)move->x,(int)move->y);
+ if (!size) goto cuddZddUndoMovesOutOfMem;
+ }
+ invmove->size = size;
+ }
+
+ return(invmoves);
+
+cuddZddUndoMovesOutOfMem:
+ while (invmoves != NULL) {
+ move = invmoves->next;
+ cuddDeallocNode(table, (DdNode *) invmoves);
+ invmoves = move;
+ }
+ return((Move *) CUDD_OUT_OF_MEM);
+
+} /* end of cuddZddUndoMoves */
+
diff --git a/src/bdd/cudd/cuddZddMisc.c b/src/bdd/cudd/cuddZddMisc.c
new file mode 100644
index 00000000..d55bb768
--- /dev/null
+++ b/src/bdd/cudd/cuddZddMisc.c
@@ -0,0 +1,252 @@
+/**CFile***********************************************************************
+
+ FileName [cuddZddMisc.c]
+
+ PackageName [cudd]
+
+ Synopsis [.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_zddDagSize()
+ <li> Cudd_zddCountMinterm()
+ <li> Cudd_zddPrintSubtable()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> cuddZddDagInt()
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [Hyong-Kyoon Shin, In-Ho Moon]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include <math.h>
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddZddMisc.c,v 1.1.1.1 2003/02/24 22:23:54 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int cuddZddDagInt ARGS((DdNode *n, st_table *tab));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the number of nodes in a ZDD.]
+
+ Description [Counts the number of nodes in a ZDD. This function
+ duplicates Cudd_DagSize and is only retained for compatibility.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DagSize]
+
+******************************************************************************/
+int
+Cudd_zddDagSize(
+ DdNode * p_node)
+{
+
+ int i;
+ st_table *table;
+
+ table = st_init_table(st_ptrcmp, st_ptrhash);
+ i = cuddZddDagInt(p_node, table);
+ st_free_table(table);
+ return(i);
+
+} /* end of Cudd_zddDagSize */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts the number of minterms of a ZDD.]
+
+ Description [Counts the number of minterms of the ZDD rooted at
+ <code>node</code>. This procedure takes a parameter
+ <code>path</code> that specifies how many variables are in the
+ support of the function. If the procedure runs out of memory, it
+ returns (double) CUDD_OUT_OF_MEM.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddCountDouble]
+
+******************************************************************************/
+double
+Cudd_zddCountMinterm(
+ DdManager * zdd,
+ DdNode * node,
+ int path)
+{
+ double dc_var, minterms;
+
+ dc_var = (double)((double)(zdd->sizeZ) - (double)path);
+ minterms = Cudd_zddCountDouble(zdd, node) / pow(2.0, dc_var);
+ return(minterms);
+
+} /* end of Cudd_zddCountMinterm */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints the ZDD table.]
+
+ Description [Prints the ZDD table for debugging purposes.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+Cudd_zddPrintSubtable(
+ DdManager * table)
+{
+ int i, j;
+ DdNode *z1, *z1_next, *base;
+ DdSubtable *ZSubTable;
+
+ base = table->one;
+ for (i = table->sizeZ - 1; i >= 0; i--) {
+ ZSubTable = &(table->subtableZ[i]);
+ printf("subtable[%d]:\n", i);
+ for (j = ZSubTable->slots - 1; j >= 0; j--) {
+ z1 = ZSubTable->nodelist[j];
+ while (z1 != NIL(DdNode)) {
+ (void) fprintf(table->out,
+#if SIZEOF_VOID_P == 8
+ "ID = 0x%lx\tindex = %d\tr = %d\t",
+ (unsigned long) z1 / (unsigned long) sizeof(DdNode),
+ z1->index, z1->ref);
+#else
+ "ID = 0x%x\tindex = %d\tr = %d\t",
+ (unsigned) z1 / (unsigned) sizeof(DdNode),
+ z1->index, z1->ref);
+#endif
+ z1_next = cuddT(z1);
+ if (Cudd_IsConstant(z1_next)) {
+ (void) fprintf(table->out, "T = %d\t\t",
+ (z1_next == base));
+ }
+ else {
+#if SIZEOF_VOID_P == 8
+ (void) fprintf(table->out, "T = 0x%lx\t",
+ (unsigned long) z1_next / (unsigned long) sizeof(DdNode));
+#else
+ (void) fprintf(table->out, "T = 0x%x\t",
+ (unsigned) z1_next / (unsigned) sizeof(DdNode));
+#endif
+ }
+ z1_next = cuddE(z1);
+ if (Cudd_IsConstant(z1_next)) {
+ (void) fprintf(table->out, "E = %d\n",
+ (z1_next == base));
+ }
+ else {
+#if SIZEOF_VOID_P == 8
+ (void) fprintf(table->out, "E = 0x%lx\n",
+ (unsigned long) z1_next / (unsigned long) sizeof(DdNode));
+#else
+ (void) fprintf(table->out, "E = 0x%x\n",
+ (unsigned) z1_next / (unsigned) sizeof(DdNode));
+#endif
+ }
+
+ z1_next = z1->next;
+ z1 = z1_next;
+ }
+ }
+ }
+ putchar('\n');
+
+} /* Cudd_zddPrintSubtable */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddDagSize.]
+
+ Description [Performs the recursive step of Cudd_zddDagSize. Does
+ not check for out-of-memory conditions.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddZddDagInt(
+ DdNode * n,
+ st_table * tab)
+{
+ if (n == NIL(DdNode))
+ return(0);
+
+ if (st_is_member(tab, (char *)n) == 1)
+ return(0);
+
+ if (Cudd_IsConstant(n))
+ return(0);
+
+ (void)st_insert(tab, (char *)n, NIL(char));
+ return(1 + cuddZddDagInt(cuddT(n), tab) +
+ cuddZddDagInt(cuddE(n), tab));
+
+} /* cuddZddDagInt */
+
diff --git a/src/bdd/cudd/cuddZddPort.c b/src/bdd/cudd/cuddZddPort.c
new file mode 100644
index 00000000..1700ab2b
--- /dev/null
+++ b/src/bdd/cudd/cuddZddPort.c
@@ -0,0 +1,354 @@
+/**CFile***********************************************************************
+
+ FileName [cuddZddPort.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions that translate BDDs to ZDDs.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_zddPortFromBdd()
+ <li> Cudd_zddPortToBdd()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> zddPortFromBddStep()
+ <li> zddPortToBddStep()
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [Hyong-kyoon Shin, In-Ho Moon]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddZddPort.c,v 1.1.1.1 2003/02/24 22:23:54 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static DdNode * zddPortFromBddStep ARGS((DdManager *dd, DdNode *B, int expected));
+static DdNode * zddPortToBddStep ARGS((DdManager *dd, DdNode *f, int depth));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Converts a BDD into a ZDD.]
+
+ Description [Converts a BDD into a ZDD. This function assumes that
+ there is a one-to-one correspondence between the BDD variables and the
+ ZDD variables, and that the variable order is the same for both types
+ of variables. These conditions are established if the ZDD variables
+ are created by one call to Cudd_zddVarsFromBddVars with multiplicity =
+ 1. Returns a pointer to the resulting ZDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddVarsFromBddVars]
+
+******************************************************************************/
+DdNode *
+Cudd_zddPortFromBdd(
+ DdManager * dd,
+ DdNode * B)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = zddPortFromBddStep(dd,B,0);
+ } while (dd->reordered == 1);
+
+ return(res);
+
+} /* end of Cudd_zddPortFromBdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Converts a ZDD into a BDD.]
+
+ Description [Converts a ZDD into a BDD. Returns a pointer to the resulting
+ ZDD if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddPortFromBdd]
+
+******************************************************************************/
+DdNode *
+Cudd_zddPortToBdd(
+ DdManager * dd,
+ DdNode * f)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = zddPortToBddStep(dd,f,0);
+ } while (dd->reordered == 1);
+
+ return(res);
+
+} /* end of Cudd_zddPortToBdd */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddPortFromBdd.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+zddPortFromBddStep(
+ DdManager * dd,
+ DdNode * B,
+ int expected)
+{
+ DdNode *res, *prevZdd, *t, *e;
+ DdNode *Breg, *Bt, *Be;
+ int id, level;
+
+ statLine(dd);
+ /* Terminal cases. */
+ if (B == Cudd_Not(DD_ONE(dd)))
+ return(DD_ZERO(dd));
+ if (B == DD_ONE(dd)) {
+ if (expected >= dd->sizeZ) {
+ return(DD_ONE(dd));
+ } else {
+ return(dd->univ[expected]);
+ }
+ }
+
+ Breg = Cudd_Regular(B);
+
+ /* Computed table look-up. */
+ res = cuddCacheLookup1Zdd(dd,Cudd_zddPortFromBdd,B);
+ if (res != NULL) {
+ level = cuddI(dd,Breg->index);
+ /* Adding DC vars. */
+ if (expected < level) {
+ /* Add suppressed variables. */
+ cuddRef(res);
+ for (level--; level >= expected; level--) {
+ prevZdd = res;
+ id = dd->invperm[level];
+ res = cuddZddGetNode(dd, id, prevZdd, prevZdd);
+ if (res == NULL) {
+ Cudd_RecursiveDerefZdd(dd, prevZdd);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDerefZdd(dd, prevZdd);
+ }
+ cuddDeref(res);
+ }
+ return(res);
+ } /* end of cache look-up */
+
+ if (Cudd_IsComplement(B)) {
+ Bt = Cudd_Not(cuddT(Breg));
+ Be = Cudd_Not(cuddE(Breg));
+ } else {
+ Bt = cuddT(Breg);
+ Be = cuddE(Breg);
+ }
+
+ id = Breg->index;
+ level = cuddI(dd,id);
+ t = zddPortFromBddStep(dd, Bt, level+1);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ e = zddPortFromBddStep(dd, Be, level+1);
+ if (e == NULL) {
+ Cudd_RecursiveDerefZdd(dd, t);
+ return(NULL);
+ }
+ cuddRef(e);
+ res = cuddZddGetNode(dd, id, t, e);
+ if (res == NULL) {
+ Cudd_RecursiveDerefZdd(dd, t);
+ Cudd_RecursiveDerefZdd(dd, e);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDerefZdd(dd, t);
+ Cudd_RecursiveDerefZdd(dd, e);
+
+ cuddCacheInsert1(dd,Cudd_zddPortFromBdd,B,res);
+
+ for (level--; level >= expected; level--) {
+ prevZdd = res;
+ id = dd->invperm[level];
+ res = cuddZddGetNode(dd, id, prevZdd, prevZdd);
+ if (res == NULL) {
+ Cudd_RecursiveDerefZdd(dd, prevZdd);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDerefZdd(dd, prevZdd);
+ }
+
+ cuddDeref(res);
+ return(res);
+
+} /* end of zddPortFromBddStep */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddPortToBdd.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+zddPortToBddStep(
+ DdManager * dd /* manager */,
+ DdNode * f /* ZDD to be converted */,
+ int depth /* recursion depth */)
+{
+ DdNode *one, *zero, *T, *E, *res, *var;
+ unsigned int index;
+ unsigned int level;
+
+ statLine(dd);
+ one = DD_ONE(dd);
+ zero = DD_ZERO(dd);
+ if (f == zero) return(Cudd_Not(one));
+
+ if (depth == dd->sizeZ) return(one);
+
+ index = dd->invpermZ[depth];
+ level = cuddIZ(dd,f->index);
+ var = cuddUniqueInter(dd,index,one,Cudd_Not(one));
+ if (var == NULL) return(NULL);
+ cuddRef(var);
+
+ if (level > (unsigned) depth) {
+ E = zddPortToBddStep(dd,f,depth+1);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd,var);
+ return(NULL);
+ }
+ cuddRef(E);
+ res = cuddBddIteRecur(dd,var,Cudd_Not(one),E);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd,var);
+ Cudd_RecursiveDeref(dd,E);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd,var);
+ Cudd_RecursiveDeref(dd,E);
+ cuddDeref(res);
+ return(res);
+ }
+
+ res = cuddCacheLookup1(dd,Cudd_zddPortToBdd,f);
+ if (res != NULL) {
+ Cudd_RecursiveDeref(dd,var);
+ return(res);
+ }
+
+ T = zddPortToBddStep(dd,cuddT(f),depth+1);
+ if (T == NULL) {
+ Cudd_RecursiveDeref(dd,var);
+ return(NULL);
+ }
+ cuddRef(T);
+ E = zddPortToBddStep(dd,cuddE(f),depth+1);
+ if (E == NULL) {
+ Cudd_RecursiveDeref(dd,var);
+ Cudd_RecursiveDeref(dd,T);
+ return(NULL);
+ }
+ cuddRef(E);
+
+ res = cuddBddIteRecur(dd,var,T,E);
+ if (res == NULL) {
+ Cudd_RecursiveDeref(dd,var);
+ Cudd_RecursiveDeref(dd,T);
+ Cudd_RecursiveDeref(dd,E);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd,var);
+ Cudd_RecursiveDeref(dd,T);
+ Cudd_RecursiveDeref(dd,E);
+ cuddDeref(res);
+
+ cuddCacheInsert1(dd,Cudd_zddPortToBdd,f,res);
+
+ return(res);
+
+} /* end of zddPortToBddStep */
+
diff --git a/src/bdd/cudd/cuddZddReord.c b/src/bdd/cudd/cuddZddReord.c
new file mode 100644
index 00000000..e14ae2ad
--- /dev/null
+++ b/src/bdd/cudd/cuddZddReord.c
@@ -0,0 +1,1633 @@
+/**CFile***********************************************************************
+
+ FileName [cuddZddReord.c]
+
+ PackageName [cudd]
+
+ Synopsis [Procedures for dynamic variable ordering of ZDDs.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_zddReduceHeap()
+ <li> Cudd_zddShuffleHeap()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddZddAlignToBdd()
+ <li> cuddZddNextHigh()
+ <li> cuddZddNextLow()
+ <li> cuddZddUniqueCompare()
+ <li> cuddZddSwapInPlace()
+ <li> cuddZddSwapping()
+ <li> cuddZddSifting()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> zddSwapAny()
+ <li> cuddZddSiftingAux()
+ <li> cuddZddSiftingUp()
+ <li> cuddZddSiftingDown()
+ <li> cuddZddSiftingBackward()
+ <li> zddReorderPreprocess()
+ <li> zddReorderPostprocess()
+ <li> zddShuffle()
+ <li> zddSiftUp()
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [Hyong-Kyoon Shin, In-Ho Moon]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define DD_MAX_SUBTABLE_SPARSITY 8
+#define DD_SHRINK_FACTOR 2
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddZddReord.c,v 1.1.1.1 2003/02/24 22:23:54 wjiang Exp $";
+#endif
+
+int *zdd_entry;
+
+int zddTotalNumberSwapping;
+
+static DdNode *empty;
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static Move * zddSwapAny ARGS((DdManager *table, int x, int y));
+static int cuddZddSiftingAux ARGS((DdManager *table, int x, int x_low, int x_high));
+static Move * cuddZddSiftingUp ARGS((DdManager *table, int x, int x_low, int initial_size));
+static Move * cuddZddSiftingDown ARGS((DdManager *table, int x, int x_high, int initial_size));
+static int cuddZddSiftingBackward ARGS((DdManager *table, Move *moves, int size));
+static void zddReorderPreprocess ARGS((DdManager *table));
+static int zddReorderPostprocess ARGS((DdManager *table));
+static int zddShuffle ARGS((DdManager *table, int *permutation));
+static int zddSiftUp ARGS((DdManager *table, int x, int xLow));
+static void zddFixTree ARGS((DdManager *table, MtrNode *treenode));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Main dynamic reordering routine for ZDDs.]
+
+ Description [Main dynamic reordering routine for ZDDs.
+ Calls one of the possible reordering procedures:
+ <ul>
+ <li>Swapping
+ <li>Sifting
+ <li>Symmetric Sifting
+ </ul>
+
+ For sifting and symmetric sifting it is possible to request reordering
+ to convergence.<p>
+
+ The core of all methods is the reordering procedure
+ cuddZddSwapInPlace() which swaps two adjacent variables.
+ Returns 1 in case of success; 0 otherwise. In the case of symmetric
+ sifting (with and without convergence) returns 1 plus the number of
+ symmetric variables, in case of success.]
+
+ SideEffects [Changes the variable order for all ZDDs and clears
+ the cache.]
+
+******************************************************************************/
+int
+Cudd_zddReduceHeap(
+ DdManager * table /* DD manager */,
+ Cudd_ReorderingType heuristic /* method used for reordering */,
+ int minsize /* bound below which no reordering occurs */)
+{
+ DdHook *hook;
+ int result;
+ unsigned int nextDyn;
+#ifdef DD_STATS
+ unsigned int initialSize;
+ unsigned int finalSize;
+#endif
+ long localTime;
+
+ /* Don't reorder if there are too many dead nodes. */
+ if (table->keysZ - table->deadZ < (unsigned) minsize)
+ return(1);
+
+ if (heuristic == CUDD_REORDER_SAME) {
+ heuristic = table->autoMethodZ;
+ }
+ if (heuristic == CUDD_REORDER_NONE) {
+ return(1);
+ }
+
+ /* This call to Cudd_zddReduceHeap does initiate reordering. Therefore
+ ** we count it.
+ */
+ table->reorderings++;
+ empty = table->zero;
+
+ localTime = util_cpu_time();
+
+ /* Run the hook functions. */
+ hook = table->preReorderingHook;
+ while (hook != NULL) {
+ int res = (hook->f)(table, "ZDD", (void *)heuristic);
+ if (res == 0) return(0);
+ hook = hook->next;
+ }
+
+ /* Clear the cache and collect garbage. */
+ zddReorderPreprocess(table);
+ zddTotalNumberSwapping = 0;
+
+#ifdef DD_STATS
+ initialSize = table->keysZ;
+
+ switch(heuristic) {
+ case CUDD_REORDER_RANDOM:
+ case CUDD_REORDER_RANDOM_PIVOT:
+ (void) fprintf(table->out,"#:I_RANDOM ");
+ break;
+ case CUDD_REORDER_SIFT:
+ case CUDD_REORDER_SIFT_CONVERGE:
+ case CUDD_REORDER_SYMM_SIFT:
+ case CUDD_REORDER_SYMM_SIFT_CONV:
+ (void) fprintf(table->out,"#:I_SIFTING ");
+ break;
+ case CUDD_REORDER_LINEAR:
+ case CUDD_REORDER_LINEAR_CONVERGE:
+ (void) fprintf(table->out,"#:I_LINSIFT ");
+ break;
+ default:
+ (void) fprintf(table->err,"Unsupported ZDD reordering method\n");
+ return(0);
+ }
+ (void) fprintf(table->out,"%8d: initial size",initialSize);
+#endif
+
+ result = cuddZddTreeSifting(table,heuristic);
+
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\n");
+ finalSize = table->keysZ;
+ (void) fprintf(table->out,"#:F_REORDER %8d: final size\n",finalSize);
+ (void) fprintf(table->out,"#:T_REORDER %8g: total time (sec)\n",
+ ((double)(util_cpu_time() - localTime)/1000.0));
+ (void) fprintf(table->out,"#:N_REORDER %8d: total swaps\n",
+ zddTotalNumberSwapping);
+#endif
+
+ if (result == 0)
+ return(0);
+
+ if (!zddReorderPostprocess(table))
+ return(0);
+
+ if (table->realignZ) {
+ if (!cuddBddAlignToZdd(table))
+ return(0);
+ }
+
+ nextDyn = table->keysZ * DD_DYN_RATIO;
+ if (table->reorderings < 20 || nextDyn > table->nextDyn)
+ table->nextDyn = nextDyn;
+ else
+ table->nextDyn += 20;
+
+ table->reordered = 1;
+
+ /* Run hook functions. */
+ hook = table->postReorderingHook;
+ while (hook != NULL) {
+ int res = (hook->f)(table, "ZDD", (void *)localTime);
+ if (res == 0) return(0);
+ hook = hook->next;
+ }
+ /* Update cumulative reordering time. */
+ table->reordTime += util_cpu_time() - localTime;
+
+ return(result);
+
+} /* end of Cudd_zddReduceHeap */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders ZDD variables according to given permutation.]
+
+ Description [Reorders ZDD variables according to given permutation.
+ The i-th entry of the permutation array contains the index of the variable
+ that should be brought to the i-th level. The size of the array should be
+ equal or greater to the number of variables currently in use.
+ Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [Changes the ZDD variable order for all diagrams and clears
+ the cache.]
+
+ SeeAlso [Cudd_zddReduceHeap]
+
+******************************************************************************/
+int
+Cudd_zddShuffleHeap(
+ DdManager * table /* DD manager */,
+ int * permutation /* required variable permutation */)
+{
+
+ int result;
+
+ empty = table->zero;
+ zddReorderPreprocess(table);
+
+ result = zddShuffle(table,permutation);
+
+ if (!zddReorderPostprocess(table)) return(0);
+
+ return(result);
+
+} /* end of Cudd_zddShuffleHeap */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders ZDD variables according to the order of the BDD
+ variables.]
+
+ Description [Reorders ZDD variables according to the order of the
+ BDD variables. This function can be called at the end of BDD
+ reordering to insure that the order of the ZDD variables is
+ consistent with the order of the BDD variables. The number of ZDD
+ variables must be a multiple of the number of BDD variables. Let
+ <code>M</code> be the ratio of the two numbers. cuddZddAlignToBdd
+ then considers the ZDD variables from <code>M*i</code> to
+ <code>(M+1)*i-1</code> as corresponding to BDD variable
+ <code>i</code>. This function should be normally called from
+ Cudd_ReduceHeap, which clears the cache. Returns 1 in case of
+ success; 0 otherwise.]
+
+ SideEffects [Changes the ZDD variable order for all diagrams and performs
+ garbage collection of the ZDD unique table.]
+
+ SeeAlso [Cudd_zddShuffleHeap Cudd_ReduceHeap]
+
+******************************************************************************/
+int
+cuddZddAlignToBdd(
+ DdManager * table /* DD manager */)
+{
+ int *invpermZ; /* permutation array */
+ int M; /* ratio of ZDD variables to BDD variables */
+ int i,j; /* loop indices */
+ int result; /* return value */
+
+ /* We assume that a ratio of 0 is OK. */
+ if (table->sizeZ == 0)
+ return(1);
+
+ empty = table->zero;
+ M = table->sizeZ / table->size;
+ /* Check whether the number of ZDD variables is a multiple of the
+ ** number of BDD variables.
+ */
+ if (M * table->size != table->sizeZ)
+ return(0);
+ /* Create and initialize the inverse permutation array. */
+ invpermZ = ALLOC(int,table->sizeZ);
+ if (invpermZ == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (i = 0; i < table->size; i++) {
+ int index = table->invperm[i];
+ int indexZ = index * M;
+ int levelZ = table->permZ[indexZ];
+ levelZ = (levelZ / M) * M;
+ for (j = 0; j < M; j++) {
+ invpermZ[M * i + j] = table->invpermZ[levelZ + j];
+ }
+ }
+ /* Eliminate dead nodes. Do not scan the cache again, because we
+ ** assume that Cudd_ReduceHeap has already cleared it.
+ */
+ cuddGarbageCollectZdd(table,0);
+
+ result = zddShuffle(table, invpermZ);
+ FREE(invpermZ);
+ /* Fix the ZDD variable group tree. */
+ zddFixTree(table,table->treeZ);
+ return(result);
+
+} /* end of cuddZddAlignToBdd */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the next subtable with a larger index.]
+
+ Description [Finds the next subtable with a larger index. Returns the
+ index.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddZddNextHigh(
+ DdManager * table,
+ int x)
+{
+ return(x + 1);
+
+} /* end of cuddZddNextHigh */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the next subtable with a smaller index.]
+
+ Description [Finds the next subtable with a smaller index. Returns the
+ index.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddZddNextLow(
+ DdManager * table,
+ int x)
+{
+ return(x - 1);
+
+} /* end of cuddZddNextLow */
+
+
+/**Function********************************************************************
+
+ Synopsis [Comparison function used by qsort.]
+
+ Description [Comparison function used by qsort to order the
+ variables according to the number of keys in the subtables.
+ Returns the difference in number of keys between the two
+ variables being compared.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddZddUniqueCompare(
+ int * ptr_x,
+ int * ptr_y)
+{
+ return(zdd_entry[*ptr_y] - zdd_entry[*ptr_x]);
+
+} /* end of cuddZddUniqueCompare */
+
+
+/**Function********************************************************************
+
+ Synopsis [Swaps two adjacent variables.]
+
+ Description [Swaps two adjacent variables. It assumes that no dead
+ nodes are present on entry to this procedure. The procedure then
+ guarantees that no dead nodes will be present when it terminates.
+ cuddZddSwapInPlace assumes that x &lt; y. Returns the number of keys in
+ the table if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddZddSwapInPlace(
+ DdManager * table,
+ int x,
+ int y)
+{
+ DdNodePtr *xlist, *ylist;
+ int xindex, yindex;
+ int xslots, yslots;
+ int xshift, yshift;
+ int oldxkeys, oldykeys;
+ int newxkeys, newykeys;
+ int i;
+ int posn;
+ DdNode *f, *f1, *f0, *f11, *f10, *f01, *f00;
+ DdNode *newf1, *newf0, *next;
+ DdNodePtr g, *lastP, *previousP;
+
+#ifdef DD_DEBUG
+ assert(x < y);
+ assert(cuddZddNextHigh(table,x) == y);
+ assert(table->subtableZ[x].keys != 0);
+ assert(table->subtableZ[y].keys != 0);
+ assert(table->subtableZ[x].dead == 0);
+ assert(table->subtableZ[y].dead == 0);
+#endif
+
+ zddTotalNumberSwapping++;
+
+ /* Get parameters of x subtable. */
+ xindex = table->invpermZ[x];
+ xlist = table->subtableZ[x].nodelist;
+ oldxkeys = table->subtableZ[x].keys;
+ xslots = table->subtableZ[x].slots;
+ xshift = table->subtableZ[x].shift;
+ newxkeys = 0;
+
+ yindex = table->invpermZ[y];
+ ylist = table->subtableZ[y].nodelist;
+ oldykeys = table->subtableZ[y].keys;
+ yslots = table->subtableZ[y].slots;
+ yshift = table->subtableZ[y].shift;
+ newykeys = oldykeys;
+
+ /* The nodes in the x layer that don't depend on y directly
+ ** will stay there; the others are put in a chain.
+ ** The chain is handled as a FIFO; g points to the beginning and
+ ** last points to the end.
+ */
+
+ g = NULL;
+ lastP = &g;
+ for (i = 0; i < xslots; i++) {
+ previousP = &(xlist[i]);
+ f = *previousP;
+ while (f != NULL) {
+ next = f->next;
+ f1 = cuddT(f); f0 = cuddE(f);
+ if ((f1->index != (DdHalfWord) yindex) &&
+ (f0->index != (DdHalfWord) yindex)) { /* stays */
+ newxkeys++;
+ *previousP = f;
+ previousP = &(f->next);
+ } else {
+ f->index = yindex;
+ *lastP = f;
+ lastP = &(f->next);
+ }
+ f = next;
+ } /* while there are elements in the collision chain */
+ *previousP = NULL;
+ } /* for each slot of the x subtable */
+ *lastP = NULL;
+
+
+#ifdef DD_COUNT
+ table->swapSteps += oldxkeys - newxkeys;
+#endif
+ /* Take care of the x nodes that must be re-expressed.
+ ** They form a linked list pointed by g. Their index has been
+ ** changed to yindex already.
+ */
+ f = g;
+ while (f != NULL) {
+ next = f->next;
+ /* Find f1, f0, f11, f10, f01, f00. */
+ f1 = cuddT(f);
+ if ((int) f1->index == yindex) {
+ f11 = cuddT(f1); f10 = cuddE(f1);
+ } else {
+ f11 = empty; f10 = f1;
+ }
+ f0 = cuddE(f);
+ if ((int) f0->index == yindex) {
+ f01 = cuddT(f0); f00 = cuddE(f0);
+ } else {
+ f01 = empty; f00 = f0;
+ }
+
+ /* Decrease ref count of f1. */
+ cuddSatDec(f1->ref);
+ /* Create the new T child. */
+ if (f11 == empty) {
+ if (f01 != empty) {
+ newf1 = f01;
+ cuddSatInc(newf1->ref);
+ }
+ /* else case was already handled when finding nodes
+ ** with both children below level y
+ */
+ } else {
+ /* Check xlist for triple (xindex, f11, f01). */
+ posn = ddHash(f11, f01, xshift);
+ /* For each element newf1 in collision list xlist[posn]. */
+ newf1 = xlist[posn];
+ while (newf1 != NULL) {
+ if (cuddT(newf1) == f11 && cuddE(newf1) == f01) {
+ cuddSatInc(newf1->ref);
+ break; /* match */
+ }
+ newf1 = newf1->next;
+ } /* while newf1 */
+ if (newf1 == NULL) { /* no match */
+ newf1 = cuddDynamicAllocNode(table);
+ if (newf1 == NULL)
+ goto zddSwapOutOfMem;
+ newf1->index = xindex; newf1->ref = 1;
+ cuddT(newf1) = f11;
+ cuddE(newf1) = f01;
+ /* Insert newf1 in the collision list xlist[pos];
+ ** increase the ref counts of f11 and f01
+ */
+ newxkeys++;
+ newf1->next = xlist[posn];
+ xlist[posn] = newf1;
+ cuddSatInc(f11->ref);
+ cuddSatInc(f01->ref);
+ }
+ }
+ cuddT(f) = newf1;
+
+ /* Do the same for f0. */
+ /* Decrease ref count of f0. */
+ cuddSatDec(f0->ref);
+ /* Create the new E child. */
+ if (f10 == empty) {
+ newf0 = f00;
+ cuddSatInc(newf0->ref);
+ } else {
+ /* Check xlist for triple (xindex, f10, f00). */
+ posn = ddHash(f10, f00, xshift);
+ /* For each element newf0 in collision list xlist[posn]. */
+ newf0 = xlist[posn];
+ while (newf0 != NULL) {
+ if (cuddT(newf0) == f10 && cuddE(newf0) == f00) {
+ cuddSatInc(newf0->ref);
+ break; /* match */
+ }
+ newf0 = newf0->next;
+ } /* while newf0 */
+ if (newf0 == NULL) { /* no match */
+ newf0 = cuddDynamicAllocNode(table);
+ if (newf0 == NULL)
+ goto zddSwapOutOfMem;
+ newf0->index = xindex; newf0->ref = 1;
+ cuddT(newf0) = f10; cuddE(newf0) = f00;
+ /* Insert newf0 in the collision list xlist[posn];
+ ** increase the ref counts of f10 and f00.
+ */
+ newxkeys++;
+ newf0->next = xlist[posn];
+ xlist[posn] = newf0;
+ cuddSatInc(f10->ref);
+ cuddSatInc(f00->ref);
+ }
+ }
+ cuddE(f) = newf0;
+
+ /* Insert the modified f in ylist.
+ ** The modified f does not already exists in ylist.
+ ** (Because of the uniqueness of the cofactors.)
+ */
+ posn = ddHash(newf1, newf0, yshift);
+ newykeys++;
+ f->next = ylist[posn];
+ ylist[posn] = f;
+ f = next;
+ } /* while f != NULL */
+
+ /* GC the y layer. */
+
+ /* For each node f in ylist. */
+ for (i = 0; i < yslots; i++) {
+ previousP = &(ylist[i]);
+ f = *previousP;
+ while (f != NULL) {
+ next = f->next;
+ if (f->ref == 0) {
+ cuddSatDec(cuddT(f)->ref);
+ cuddSatDec(cuddE(f)->ref);
+ cuddDeallocNode(table, f);
+ newykeys--;
+ } else {
+ *previousP = f;
+ previousP = &(f->next);
+ }
+ f = next;
+ } /* while f */
+ *previousP = NULL;
+ } /* for i */
+
+ /* Set the appropriate fields in table. */
+ table->subtableZ[x].nodelist = ylist;
+ table->subtableZ[x].slots = yslots;
+ table->subtableZ[x].shift = yshift;
+ table->subtableZ[x].keys = newykeys;
+ table->subtableZ[x].maxKeys = yslots * DD_MAX_SUBTABLE_DENSITY;
+
+ table->subtableZ[y].nodelist = xlist;
+ table->subtableZ[y].slots = xslots;
+ table->subtableZ[y].shift = xshift;
+ table->subtableZ[y].keys = newxkeys;
+ table->subtableZ[y].maxKeys = xslots * DD_MAX_SUBTABLE_DENSITY;
+
+ table->permZ[xindex] = y; table->permZ[yindex] = x;
+ table->invpermZ[x] = yindex; table->invpermZ[y] = xindex;
+
+ table->keysZ += newxkeys + newykeys - oldxkeys - oldykeys;
+
+ /* Update univ section; univ[x] remains the same. */
+ table->univ[y] = cuddT(table->univ[x]);
+
+ return (table->keysZ);
+
+zddSwapOutOfMem:
+ (void) fprintf(table->err, "Error: cuddZddSwapInPlace out of memory\n");
+
+ return (0);
+
+} /* end of cuddZddSwapInPlace */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders variables by a sequence of (non-adjacent) swaps.]
+
+ Description [Implementation of Plessier's algorithm that reorders
+ variables by a sequence of (non-adjacent) swaps.
+ <ol>
+ <li> Select two variables (RANDOM or HEURISTIC).
+ <li> Permute these variables.
+ <li> If the nodes have decreased accept the permutation.
+ <li> Otherwise reconstruct the original heap.
+ <li> Loop.
+ </ol>
+ Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddZddSwapping(
+ DdManager * table,
+ int lower,
+ int upper,
+ Cudd_ReorderingType heuristic)
+{
+ int i, j;
+ int max, keys;
+ int nvars;
+ int x, y;
+ int iterate;
+ int previousSize;
+ Move *moves, *move;
+ int pivot;
+ int modulo;
+ int result;
+
+#ifdef DD_DEBUG
+ /* Sanity check */
+ assert(lower >= 0 && upper < table->sizeZ && lower <= upper);
+#endif
+
+ nvars = upper - lower + 1;
+ iterate = nvars;
+
+ for (i = 0; i < iterate; i++) {
+ if (heuristic == CUDD_REORDER_RANDOM_PIVOT) {
+ /* Find pivot <= id with maximum keys. */
+ for (max = -1, j = lower; j <= upper; j++) {
+ if ((keys = table->subtableZ[j].keys) > max) {
+ max = keys;
+ pivot = j;
+ }
+ }
+
+ modulo = upper - pivot;
+ if (modulo == 0) {
+ y = pivot; /* y = nvars-1 */
+ } else {
+ /* y = random # from {pivot+1 .. nvars-1} */
+ y = pivot + 1 + (int) (Cudd_Random() % modulo);
+ }
+
+ modulo = pivot - lower - 1;
+ if (modulo < 1) { /* if pivot = 1 or 0 */
+ x = lower;
+ } else {
+ do { /* x = random # from {0 .. pivot-2} */
+ x = (int) Cudd_Random() % modulo;
+ } while (x == y);
+ /* Is this condition really needed, since x and y
+ are in regions separated by pivot? */
+ }
+ } else {
+ x = (int) (Cudd_Random() % nvars) + lower;
+ do {
+ y = (int) (Cudd_Random() % nvars) + lower;
+ } while (x == y);
+ }
+
+ previousSize = table->keysZ;
+ moves = zddSwapAny(table, x, y);
+ if (moves == NULL)
+ goto cuddZddSwappingOutOfMem;
+
+ result = cuddZddSiftingBackward(table, moves, previousSize);
+ if (!result)
+ goto cuddZddSwappingOutOfMem;
+
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+#ifdef DD_STATS
+ if (table->keysZ < (unsigned) previousSize) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keysZ > (unsigned) previousSize) {
+ (void) fprintf(table->out,"+"); /* should never happen */
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+
+ return(1);
+
+cuddZddSwappingOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *) moves);
+ moves = move;
+ }
+ return(0);
+
+} /* end of cuddZddSwapping */
+
+
+/**Function********************************************************************
+
+ Synopsis [Implementation of Rudell's sifting algorithm.]
+
+ Description [Implementation of Rudell's sifting algorithm.
+ Assumes that no dead nodes are present.
+ <ol>
+ <li> Order all the variables according to the number of entries
+ in each unique table.
+ <li> Sift the variable up and down, remembering each time the
+ total size of the DD heap.
+ <li> Select the best permutation.
+ <li> Repeat 3 and 4 for all variables.
+ </ol>
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddZddSifting(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int i;
+ int *var;
+ int size;
+ int x;
+ int result;
+#ifdef DD_STATS
+ int previousSize;
+#endif
+
+ size = table->sizeZ;
+
+ /* Find order in which to sift variables. */
+ var = NULL;
+ zdd_entry = ALLOC(int, size);
+ if (zdd_entry == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto cuddZddSiftingOutOfMem;
+ }
+ var = ALLOC(int, size);
+ if (var == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto cuddZddSiftingOutOfMem;
+ }
+
+ for (i = 0; i < size; i++) {
+ x = table->permZ[i];
+ zdd_entry[i] = table->subtableZ[x].keys;
+ var[i] = i;
+ }
+
+ qsort((void *)var, size, sizeof(int), (int (*)(const void *, const void *))cuddZddUniqueCompare);
+
+ /* Now sift. */
+ for (i = 0; i < ddMin(table->siftMaxVar, size); i++) {
+ if (zddTotalNumberSwapping >= table->siftMaxSwap)
+ break;
+ x = table->permZ[var[i]];
+ if (x < lower || x > upper) continue;
+#ifdef DD_STATS
+ previousSize = table->keysZ;
+#endif
+ result = cuddZddSiftingAux(table, x, lower, upper);
+ if (!result)
+ goto cuddZddSiftingOutOfMem;
+#ifdef DD_STATS
+ if (table->keysZ < (unsigned) previousSize) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keysZ > (unsigned) previousSize) {
+ (void) fprintf(table->out,"+"); /* should never happen */
+ (void) fprintf(table->out,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keysZ , var[i]);
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+
+ FREE(var);
+ FREE(zdd_entry);
+
+ return(1);
+
+cuddZddSiftingOutOfMem:
+
+ if (zdd_entry != NULL) FREE(zdd_entry);
+ if (var != NULL) FREE(var);
+
+ return(0);
+
+} /* end of cuddZddSifting */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Swaps any two variables.]
+
+ Description [Swaps any two variables. Returns the set of moves.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static Move *
+zddSwapAny(
+ DdManager * table,
+ int x,
+ int y)
+{
+ Move *move, *moves;
+ int tmp, size;
+ int x_ref, y_ref;
+ int x_next, y_next;
+ int limit_size;
+
+ if (x > y) { /* make x precede y */
+ tmp = x; x = y; y = tmp;
+ }
+
+ x_ref = x; y_ref = y;
+
+ x_next = cuddZddNextHigh(table, x);
+ y_next = cuddZddNextLow(table, y);
+ moves = NULL;
+ limit_size = table->keysZ;
+
+ for (;;) {
+ if (x_next == y_next) { /* x < x_next = y_next < y */
+ size = cuddZddSwapInPlace(table, x, x_next);
+ if (size == 0)
+ goto zddSwapAnyOutOfMem;
+ move = (Move *) cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto zddSwapAnyOutOfMem;
+ move->x = x;
+ move->y = x_next;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+
+ size = cuddZddSwapInPlace(table, y_next, y);
+ if (size == 0)
+ goto zddSwapAnyOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto zddSwapAnyOutOfMem;
+ move->x = y_next;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+
+ size = cuddZddSwapInPlace(table, x, x_next);
+ if (size == 0)
+ goto zddSwapAnyOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto zddSwapAnyOutOfMem;
+ move->x = x;
+ move->y = x_next;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+
+ tmp = x; x = y; y = tmp;
+
+ } else if (x == y_next) { /* x = y_next < y = x_next */
+ size = cuddZddSwapInPlace(table, x, x_next);
+ if (size == 0)
+ goto zddSwapAnyOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto zddSwapAnyOutOfMem;
+ move->x = x;
+ move->y = x_next;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+
+ tmp = x; x = y; y = tmp;
+ } else {
+ size = cuddZddSwapInPlace(table, x, x_next);
+ if (size == 0)
+ goto zddSwapAnyOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto zddSwapAnyOutOfMem;
+ move->x = x;
+ move->y = x_next;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+
+ size = cuddZddSwapInPlace(table, y_next, y);
+ if (size == 0)
+ goto zddSwapAnyOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto zddSwapAnyOutOfMem;
+ move->x = y_next;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+
+ x = x_next; y = y_next;
+ }
+
+ x_next = cuddZddNextHigh(table, x);
+ y_next = cuddZddNextLow(table, y);
+ if (x_next > y_ref)
+ break; /* if x == y_ref */
+
+ if ((double) size > table->maxGrowth * (double) limit_size)
+ break;
+ if (size < limit_size)
+ limit_size = size;
+ }
+ if (y_next >= x_ref) {
+ size = cuddZddSwapInPlace(table, y_next, y);
+ if (size == 0)
+ goto zddSwapAnyOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto zddSwapAnyOutOfMem;
+ move->x = y_next;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ }
+
+ return(moves);
+
+zddSwapAnyOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *)moves);
+ moves = move;
+ }
+ return(NULL);
+
+} /* end of zddSwapAny */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given xLow <= x <= xHigh moves x up and down between the
+ boundaries.]
+
+ Description [Given xLow <= x <= xHigh moves x up and down between the
+ boundaries. Finds the best position and does the required changes.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddZddSiftingAux(
+ DdManager * table,
+ int x,
+ int x_low,
+ int x_high)
+{
+ Move *move;
+ Move *moveUp; /* list of up move */
+ Move *moveDown; /* list of down move */
+
+ int initial_size;
+ int result;
+
+ initial_size = table->keysZ;
+
+#ifdef DD_DEBUG
+ assert(table->subtableZ[x].keys > 0);
+#endif
+
+ moveDown = NULL;
+ moveUp = NULL;
+
+ if (x == x_low) {
+ moveDown = cuddZddSiftingDown(table, x, x_high, initial_size);
+ /* after that point x --> x_high */
+ if (moveDown == NULL)
+ goto cuddZddSiftingAuxOutOfMem;
+ result = cuddZddSiftingBackward(table, moveDown,
+ initial_size);
+ /* move backward and stop at best position */
+ if (!result)
+ goto cuddZddSiftingAuxOutOfMem;
+
+ }
+ else if (x == x_high) {
+ moveUp = cuddZddSiftingUp(table, x, x_low, initial_size);
+ /* after that point x --> x_low */
+ if (moveUp == NULL)
+ goto cuddZddSiftingAuxOutOfMem;
+ result = cuddZddSiftingBackward(table, moveUp, initial_size);
+ /* move backward and stop at best position */
+ if (!result)
+ goto cuddZddSiftingAuxOutOfMem;
+ }
+ else if ((x - x_low) > (x_high - x)) {
+ /* must go down first:shorter */
+ moveDown = cuddZddSiftingDown(table, x, x_high, initial_size);
+ /* after that point x --> x_high */
+ if (moveDown == NULL)
+ goto cuddZddSiftingAuxOutOfMem;
+ moveUp = cuddZddSiftingUp(table, moveDown->y, x_low,
+ initial_size);
+ if (moveUp == NULL)
+ goto cuddZddSiftingAuxOutOfMem;
+ result = cuddZddSiftingBackward(table, moveUp, initial_size);
+ /* move backward and stop at best position */
+ if (!result)
+ goto cuddZddSiftingAuxOutOfMem;
+ }
+ else {
+ moveUp = cuddZddSiftingUp(table, x, x_low, initial_size);
+ /* after that point x --> x_high */
+ if (moveUp == NULL)
+ goto cuddZddSiftingAuxOutOfMem;
+ moveDown = cuddZddSiftingDown(table, moveUp->x, x_high,
+ initial_size);
+ /* then move up */
+ if (moveDown == NULL)
+ goto cuddZddSiftingAuxOutOfMem;
+ result = cuddZddSiftingBackward(table, moveDown,
+ initial_size);
+ /* move backward and stop at best position */
+ if (!result)
+ goto cuddZddSiftingAuxOutOfMem;
+ }
+
+ while (moveDown != NULL) {
+ move = moveDown->next;
+ cuddDeallocNode(table, (DdNode *)moveDown);
+ moveDown = move;
+ }
+ while (moveUp != NULL) {
+ move = moveUp->next;
+ cuddDeallocNode(table, (DdNode *)moveUp);
+ moveUp = move;
+ }
+
+ return(1);
+
+cuddZddSiftingAuxOutOfMem:
+ while (moveDown != NULL) {
+ move = moveDown->next;
+ cuddDeallocNode(table, (DdNode *)moveDown);
+ moveDown = move;
+ }
+ while (moveUp != NULL) {
+ move = moveUp->next;
+ cuddDeallocNode(table, (DdNode *)moveUp);
+ moveUp = move;
+ }
+
+ return(0);
+
+} /* end of cuddZddSiftingAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts a variable up.]
+
+ Description [Sifts a variable up. Moves y up until either it reaches
+ the bound (x_low) or the size of the ZDD heap increases too much.
+ Returns the set of moves in case of success; NULL if memory is full.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static Move *
+cuddZddSiftingUp(
+ DdManager * table,
+ int x,
+ int x_low,
+ int initial_size)
+{
+ Move *moves;
+ Move *move;
+ int y;
+ int size;
+ int limit_size = initial_size;
+
+ moves = NULL;
+ y = cuddZddNextLow(table, x);
+ while (y >= x_low) {
+ size = cuddZddSwapInPlace(table, y, x);
+ if (size == 0)
+ goto cuddZddSiftingUpOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto cuddZddSiftingUpOutOfMem;
+ move->x = y;
+ move->y = x;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+
+ if ((double)size > (double)limit_size * table->maxGrowth)
+ break;
+ if (size < limit_size)
+ limit_size = size;
+
+ x = y;
+ y = cuddZddNextLow(table, x);
+ }
+ return(moves);
+
+cuddZddSiftingUpOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *)moves);
+ moves = move;
+ }
+ return(NULL);
+
+} /* end of cuddZddSiftingUp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Sifts a variable down.]
+
+ Description [Sifts a variable down. Moves x down until either it
+ reaches the bound (x_high) or the size of the ZDD heap increases too
+ much. Returns the set of moves in case of success; NULL if memory is
+ full.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static Move *
+cuddZddSiftingDown(
+ DdManager * table,
+ int x,
+ int x_high,
+ int initial_size)
+{
+ Move *moves;
+ Move *move;
+ int y;
+ int size;
+ int limit_size = initial_size;
+
+ moves = NULL;
+ y = cuddZddNextHigh(table, x);
+ while (y <= x_high) {
+ size = cuddZddSwapInPlace(table, x, y);
+ if (size == 0)
+ goto cuddZddSiftingDownOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto cuddZddSiftingDownOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+
+ if ((double)size > (double)limit_size * table->maxGrowth)
+ break;
+ if (size < limit_size)
+ limit_size = size;
+
+ x = y;
+ y = cuddZddNextHigh(table, x);
+ }
+ return(moves);
+
+cuddZddSiftingDownOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *)moves);
+ moves = move;
+ }
+ return(NULL);
+
+} /* end of cuddZddSiftingDown */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given a set of moves, returns the ZDD heap to the position
+ giving the minimum size.]
+
+ Description [Given a set of moves, returns the ZDD heap to the
+ position giving the minimum size. In case of ties, returns to the
+ closest position giving the minimum size. Returns 1 in case of
+ success; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddZddSiftingBackward(
+ DdManager * table,
+ Move * moves,
+ int size)
+{
+ int i;
+ int i_best;
+ Move *move;
+ int res;
+
+ /* Find the minimum size among moves. */
+ i_best = -1;
+ for (move = moves, i = 0; move != NULL; move = move->next, i++) {
+ if (move->size < size) {
+ i_best = i;
+ size = move->size;
+ }
+ }
+
+ for (move = moves, i = 0; move != NULL; move = move->next, i++) {
+ if (i == i_best)
+ break;
+ res = cuddZddSwapInPlace(table, move->x, move->y);
+ if (!res)
+ return(0);
+ if (i_best == -1 && res == size)
+ break;
+ }
+
+ return(1);
+
+} /* end of cuddZddSiftingBackward */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prepares the ZDD heap for dynamic reordering.]
+
+ Description [Prepares the ZDD heap for dynamic reordering. Does
+ garbage collection, to guarantee that there are no dead nodes;
+ and clears the cache, which is invalidated by dynamic reordering.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static void
+zddReorderPreprocess(
+ DdManager * table)
+{
+
+ /* Clear the cache. */
+ cuddCacheFlush(table);
+
+ /* Eliminate dead nodes. Do not scan the cache again. */
+ cuddGarbageCollectZdd(table,0);
+
+ return;
+
+} /* end of ddReorderPreprocess */
+
+
+/**Function********************************************************************
+
+ Synopsis [Shrinks almost empty ZDD subtables at the end of reordering
+ to guarantee that they have a reasonable load factor.]
+
+ Description [Shrinks almost empty subtables at the end of reordering to
+ guarantee that they have a reasonable load factor. However, if there many
+ nodes are being reclaimed, then no resizing occurs. Returns 1 in case of
+ success; 0 otherwise.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static int
+zddReorderPostprocess(
+ DdManager * table)
+{
+ int i, j, posn;
+ DdNodePtr *nodelist, *oldnodelist;
+ DdNode *node, *next;
+ unsigned int slots, oldslots;
+ extern void (*MMoutOfMemory)(long);
+ void (*saveHandler)(long);
+
+#ifdef DD_VERBOSE
+ (void) fflush(table->out);
+#endif
+
+ /* If we have very many reclaimed nodes, we do not want to shrink
+ ** the subtables, because this will lead to more garbage
+ ** collections. More garbage collections mean shorter mean life for
+ ** nodes with zero reference count; hence lower probability of finding
+ ** a result in the cache.
+ */
+ if (table->reclaimed > table->allocated * 0.5) return(1);
+
+ /* Resize subtables. */
+ for (i = 0; i < table->sizeZ; i++) {
+ int shift;
+ oldslots = table->subtableZ[i].slots;
+ if (oldslots < table->subtableZ[i].keys * DD_MAX_SUBTABLE_SPARSITY ||
+ oldslots <= table->initSlots) continue;
+ oldnodelist = table->subtableZ[i].nodelist;
+ slots = oldslots >> 1;
+ saveHandler = MMoutOfMemory;
+ MMoutOfMemory = Cudd_OutOfMem;
+ nodelist = ALLOC(DdNodePtr, slots);
+ MMoutOfMemory = saveHandler;
+ if (nodelist == NULL) {
+ return(1);
+ }
+ table->subtableZ[i].nodelist = nodelist;
+ table->subtableZ[i].slots = slots;
+ table->subtableZ[i].shift++;
+ table->subtableZ[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
+#ifdef DD_VERBOSE
+ (void) fprintf(table->err,
+ "shrunk layer %d (%d keys) from %d to %d slots\n",
+ i, table->subtableZ[i].keys, oldslots, slots);
+#endif
+
+ for (j = 0; (unsigned) j < slots; j++) {
+ nodelist[j] = NULL;
+ }
+ shift = table->subtableZ[i].shift;
+ for (j = 0; (unsigned) j < oldslots; j++) {
+ node = oldnodelist[j];
+ while (node != NULL) {
+ next = node->next;
+ posn = ddHash(cuddT(node), cuddE(node), shift);
+ node->next = nodelist[posn];
+ nodelist[posn] = node;
+ node = next;
+ }
+ }
+ FREE(oldnodelist);
+
+ table->memused += (slots - oldslots) * sizeof(DdNode *);
+ table->slots += slots - oldslots;
+ table->minDead = (unsigned) (table->gcFrac * (double) table->slots);
+ table->cacheSlack = (int) ddMin(table->maxCacheHard,
+ DD_MAX_CACHE_TO_SLOTS_RATIO*table->slots) -
+ 2 * (int) table->cacheSlots;
+ }
+ /* We don't look at the constant subtable, because it is not
+ ** affected by reordering.
+ */
+
+ return(1);
+
+} /* end of zddReorderPostprocess */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reorders ZDD variables according to a given permutation.]
+
+ Description [Reorders ZDD variables according to a given permutation.
+ The i-th permutation array contains the index of the variable that
+ should be brought to the i-th level. zddShuffle assumes that no
+ dead nodes are present. The reordering is achieved by a series of
+ upward sifts. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+zddShuffle(
+ DdManager * table,
+ int * permutation)
+{
+ int index;
+ int level;
+ int position;
+ int numvars;
+ int result;
+#ifdef DD_STATS
+ long localTime;
+ int initialSize;
+ int finalSize;
+ int previousSize;
+#endif
+
+ zddTotalNumberSwapping = 0;
+#ifdef DD_STATS
+ localTime = util_cpu_time();
+ initialSize = table->keysZ;
+ (void) fprintf(table->out,"#:I_SHUFFLE %8d: initial size\n",
+ initialSize);
+#endif
+
+ numvars = table->sizeZ;
+
+ for (level = 0; level < numvars; level++) {
+ index = permutation[level];
+ position = table->permZ[index];
+#ifdef DD_STATS
+ previousSize = table->keysZ;
+#endif
+ result = zddSiftUp(table,position,level);
+ if (!result) return(0);
+#ifdef DD_STATS
+ if (table->keysZ < (unsigned) previousSize) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keysZ > (unsigned) previousSize) {
+ (void) fprintf(table->out,"+"); /* should never happen */
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\n");
+ finalSize = table->keysZ;
+ (void) fprintf(table->out,"#:F_SHUFFLE %8d: final size\n",finalSize);
+ (void) fprintf(table->out,"#:T_SHUFFLE %8g: total time (sec)\n",
+ ((double)(util_cpu_time() - localTime)/1000.0));
+ (void) fprintf(table->out,"#:N_SHUFFLE %8d: total swaps\n",
+ zddTotalNumberSwapping);
+#endif
+
+ return(1);
+
+} /* end of zddShuffle */
+
+
+/**Function********************************************************************
+
+ Synopsis [Moves one ZDD variable up.]
+
+ Description [Takes a ZDD variable from position x and sifts it up to
+ position xLow; xLow should be less than or equal to x.
+ Returns 1 if successful; 0 otherwise]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+zddSiftUp(
+ DdManager * table,
+ int x,
+ int xLow)
+{
+ int y;
+ int size;
+
+ y = cuddZddNextLow(table,x);
+ while (y >= xLow) {
+ size = cuddZddSwapInPlace(table,y,x);
+ if (size == 0) {
+ return(0);
+ }
+ x = y;
+ y = cuddZddNextLow(table,x);
+ }
+ return(1);
+
+} /* end of zddSiftUp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Fixes the ZDD variable group tree after a shuffle.]
+
+ Description [Fixes the ZDD variable group tree after a
+ shuffle. Assumes that the order of the variables in a terminal node
+ has not been changed.]
+
+ SideEffects [Changes the ZDD variable group tree.]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+zddFixTree(
+ DdManager * table,
+ MtrNode * treenode)
+{
+ if (treenode == NULL) return;
+ treenode->low = ((int) treenode->index < table->sizeZ) ?
+ table->permZ[treenode->index] : treenode->index;
+ if (treenode->child != NULL) {
+ zddFixTree(table, treenode->child);
+ }
+ if (treenode->younger != NULL)
+ zddFixTree(table, treenode->younger);
+ if (treenode->parent != NULL && treenode->low < treenode->parent->low) {
+ treenode->parent->low = treenode->low;
+ treenode->parent->index = treenode->index;
+ }
+ return;
+
+} /* end of zddFixTree */
+
diff --git a/src/bdd/cudd/cuddZddSetop.c b/src/bdd/cudd/cuddZddSetop.c
new file mode 100644
index 00000000..cf05210f
--- /dev/null
+++ b/src/bdd/cudd/cuddZddSetop.c
@@ -0,0 +1,1137 @@
+/**CFile***********************************************************************
+
+ FileName [cuddZddSetop.c]
+
+ PackageName [cudd]
+
+ Synopsis [Set operations on ZDDs.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_zddIte()
+ <li> Cudd_zddUnion()
+ <li> Cudd_zddIntersect()
+ <li> Cudd_zddDiff()
+ <li> Cudd_zddDiffConst()
+ <li> Cudd_zddSubset1()
+ <li> Cudd_zddSubset0()
+ <li> Cudd_zddChange()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddZddIte()
+ <li> cuddZddUnion()
+ <li> cuddZddIntersect()
+ <li> cuddZddDiff()
+ <li> cuddZddChangeAux()
+ <li> cuddZddSubset1()
+ <li> cuddZddSubset0()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> zdd_subset1_aux()
+ <li> zdd_subset0_aux()
+ <li> zddVarToConst()
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [Hyong-Kyoon Shin, In-Ho Moon]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddZddSetop.c,v 1.1.1.1 2003/02/24 22:23:54 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static DdNode * zdd_subset1_aux ARGS((DdManager *zdd, DdNode *P, DdNode *zvar));
+static DdNode * zdd_subset0_aux ARGS((DdManager *zdd, DdNode *P, DdNode *zvar));
+static void zddVarToConst ARGS((DdNode *f, DdNode **gp, DdNode **hp, DdNode *base, DdNode *empty));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the ITE of three ZDDs.]
+
+ Description [Computes the ITE of three ZDDs. Returns a pointer to the
+ result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_zddIte(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ DdNode * h)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddZddIte(dd, f, g, h);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_zddIte */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the union of two ZDDs.]
+
+ Description [Computes the union of two ZDDs. Returns a pointer to the
+ result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_zddUnion(
+ DdManager * dd,
+ DdNode * P,
+ DdNode * Q)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddZddUnion(dd, P, Q);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_zddUnion */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the intersection of two ZDDs.]
+
+ Description [Computes the intersection of two ZDDs. Returns a pointer to
+ the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_zddIntersect(
+ DdManager * dd,
+ DdNode * P,
+ DdNode * Q)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddZddIntersect(dd, P, Q);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_zddIntersect */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the difference of two ZDDs.]
+
+ Description [Computes the difference of two ZDDs. Returns a pointer to the
+ result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddDiffConst]
+
+******************************************************************************/
+DdNode *
+Cudd_zddDiff(
+ DdManager * dd,
+ DdNode * P,
+ DdNode * Q)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddZddDiff(dd, P, Q);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_zddDiff */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the inclusion test for ZDDs (P implies Q).]
+
+ Description [Inclusion test for ZDDs (P implies Q). No new nodes are
+ generated by this procedure. Returns empty if true;
+ a valid pointer different from empty or DD_NON_CONSTANT otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddDiff]
+
+******************************************************************************/
+DdNode *
+Cudd_zddDiffConst(
+ DdManager * zdd,
+ DdNode * P,
+ DdNode * Q)
+{
+ int p_top, q_top;
+ DdNode *empty = DD_ZERO(zdd), *t, *res;
+ DdManager *table = zdd;
+
+ statLine(zdd);
+ if (P == empty)
+ return(empty);
+ if (Q == empty)
+ return(P);
+ if (P == Q)
+ return(empty);
+
+ /* Check cache. The cache is shared by cuddZddDiff(). */
+ res = cuddCacheLookup2Zdd(table, cuddZddDiff, P, Q);
+ if (res != NULL)
+ return(res);
+
+ if (cuddIsConstant(P))
+ p_top = P->index;
+ else
+ p_top = zdd->permZ[P->index];
+ if (cuddIsConstant(Q))
+ q_top = Q->index;
+ else
+ q_top = zdd->permZ[Q->index];
+ if (p_top < q_top) {
+ res = DD_NON_CONSTANT;
+ } else if (p_top > q_top) {
+ res = Cudd_zddDiffConst(zdd, P, cuddE(Q));
+ } else {
+ t = Cudd_zddDiffConst(zdd, cuddT(P), cuddT(Q));
+ if (t != empty)
+ res = DD_NON_CONSTANT;
+ else
+ res = Cudd_zddDiffConst(zdd, cuddE(P), cuddE(Q));
+ }
+
+ cuddCacheInsert2(table, cuddZddDiff, P, Q, res);
+
+ return(res);
+
+} /* end of Cudd_zddDiffConst */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the positive cofactor of a ZDD w.r.t. a variable.]
+
+ Description [Computes the positive cofactor of a ZDD w.r.t. a
+ variable. In terms of combinations, the result is the set of all
+ combinations in which the variable is asserted. Returns a pointer to
+ the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddSubset0]
+
+******************************************************************************/
+DdNode *
+Cudd_zddSubset1(
+ DdManager * dd,
+ DdNode * P,
+ int var)
+{
+ DdNode *r;
+
+ do {
+ dd->reordered = 0;
+ r = cuddZddSubset1(dd, P, var);
+ } while (dd->reordered == 1);
+
+ return(r);
+
+} /* end of Cudd_zddSubset1 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the negative cofactor of a ZDD w.r.t. a variable.]
+
+ Description [Computes the negative cofactor of a ZDD w.r.t. a
+ variable. In terms of combinations, the result is the set of all
+ combinations in which the variable is negated. Returns a pointer to
+ the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddSubset1]
+
+******************************************************************************/
+DdNode *
+Cudd_zddSubset0(
+ DdManager * dd,
+ DdNode * P,
+ int var)
+{
+ DdNode *r;
+
+ do {
+ dd->reordered = 0;
+ r = cuddZddSubset0(dd, P, var);
+ } while (dd->reordered == 1);
+
+ return(r);
+
+} /* end of Cudd_zddSubset0 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Substitutes a variable with its complement in a ZDD.]
+
+ Description [Substitutes a variable with its complement in a ZDD.
+ returns a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_zddChange(
+ DdManager * dd,
+ DdNode * P,
+ int var)
+{
+ DdNode *res;
+
+ if ((unsigned int) var >= CUDD_MAXINDEX - 1) return(NULL);
+
+ do {
+ dd->reordered = 0;
+ res = cuddZddChange(dd, P, var);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_zddChange */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddIte.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+cuddZddIte(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * g,
+ DdNode * h)
+{
+ DdNode *tautology, *empty;
+ DdNode *r,*Gv,*Gvn,*Hv,*Hvn,*t,*e;
+ unsigned int topf,topg,toph,v,top;
+ int index;
+
+ statLine(dd);
+ /* Trivial cases. */
+ /* One variable cases. */
+ if (f == (empty = DD_ZERO(dd))) { /* ITE(0,G,H) = H */
+ return(h);
+ }
+ topf = cuddIZ(dd,f->index);
+ topg = cuddIZ(dd,g->index);
+ toph = cuddIZ(dd,h->index);
+ v = ddMin(topg,toph);
+ top = ddMin(topf,v);
+
+ tautology = (top == CUDD_MAXINDEX) ? DD_ONE(dd) : dd->univ[top];
+ if (f == tautology) { /* ITE(1,G,H) = G */
+ return(g);
+ }
+
+ /* From now on, f is known to not be a constant. */
+ zddVarToConst(f,&g,&h,tautology,empty);
+
+ /* Check remaining one variable cases. */
+ if (g == h) { /* ITE(F,G,G) = G */
+ return(g);
+ }
+
+ if (g == tautology) { /* ITE(F,1,0) = F */
+ if (h == empty) return(f);
+ }
+
+ /* Check cache. */
+ r = cuddCacheLookupZdd(dd,DD_ZDD_ITE_TAG,f,g,h);
+ if (r != NULL) {
+ return(r);
+ }
+
+ /* Recompute these because they may have changed in zddVarToConst. */
+ topg = cuddIZ(dd,g->index);
+ toph = cuddIZ(dd,h->index);
+ v = ddMin(topg,toph);
+
+ if (topf < v) {
+ r = cuddZddIte(dd,cuddE(f),g,h);
+ if (r == NULL) return(NULL);
+ } else if (topf > v) {
+ if (topg > v) {
+ Gvn = g;
+ index = h->index;
+ } else {
+ Gvn = cuddE(g);
+ index = g->index;
+ }
+ if (toph > v) {
+ Hv = empty; Hvn = h;
+ } else {
+ Hv = cuddT(h); Hvn = cuddE(h);
+ }
+ e = cuddZddIte(dd,f,Gvn,Hvn);
+ if (e == NULL) return(NULL);
+ cuddRef(e);
+ r = cuddZddGetNode(dd,index,Hv,e);
+ if (r == NULL) {
+ Cudd_RecursiveDerefZdd(dd,e);
+ return(NULL);
+ }
+ cuddDeref(e);
+ } else {
+ index = f->index;
+ if (topg > v) {
+ Gv = empty; Gvn = g;
+ } else {
+ Gv = cuddT(g); Gvn = cuddE(g);
+ }
+ if (toph > v) {
+ Hv = empty; Hvn = h;
+ } else {
+ Hv = cuddT(h); Hvn = cuddE(h);
+ }
+ e = cuddZddIte(dd,cuddE(f),Gvn,Hvn);
+ if (e == NULL) return(NULL);
+ cuddRef(e);
+ t = cuddZddIte(dd,cuddT(f),Gv,Hv);
+ if (t == NULL) {
+ Cudd_RecursiveDerefZdd(dd,e);
+ return(NULL);
+ }
+ cuddRef(t);
+ r = cuddZddGetNode(dd,index,t,e);
+ if (r == NULL) {
+ Cudd_RecursiveDerefZdd(dd,e);
+ Cudd_RecursiveDerefZdd(dd,t);
+ return(NULL);
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+ }
+
+ cuddCacheInsert(dd,DD_ZDD_ITE_TAG,f,g,h,r);
+
+ return(r);
+
+} /* end of cuddZddIte */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddUnion.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+cuddZddUnion(
+ DdManager * zdd,
+ DdNode * P,
+ DdNode * Q)
+{
+ int p_top, q_top;
+ DdNode *empty = DD_ZERO(zdd), *t, *e, *res;
+ DdManager *table = zdd;
+
+ statLine(zdd);
+ if (P == empty)
+ return(Q);
+ if (Q == empty)
+ return(P);
+ if (P == Q)
+ return(P);
+
+ /* Check cache */
+ res = cuddCacheLookup2Zdd(table, cuddZddUnion, P, Q);
+ if (res != NULL)
+ return(res);
+
+ if (cuddIsConstant(P))
+ p_top = P->index;
+ else
+ p_top = zdd->permZ[P->index];
+ if (cuddIsConstant(Q))
+ q_top = Q->index;
+ else
+ q_top = zdd->permZ[Q->index];
+ if (p_top < q_top) {
+ e = cuddZddUnion(zdd, cuddE(P), Q);
+ if (e == NULL) return (NULL);
+ cuddRef(e);
+ res = cuddZddGetNode(zdd, P->index, cuddT(P), e);
+ if (res == NULL) {
+ Cudd_RecursiveDerefZdd(table, e);
+ return(NULL);
+ }
+ cuddDeref(e);
+ } else if (p_top > q_top) {
+ e = cuddZddUnion(zdd, P, cuddE(Q));
+ if (e == NULL) return(NULL);
+ cuddRef(e);
+ res = cuddZddGetNode(zdd, Q->index, cuddT(Q), e);
+ if (res == NULL) {
+ Cudd_RecursiveDerefZdd(table, e);
+ return(NULL);
+ }
+ cuddDeref(e);
+ } else {
+ t = cuddZddUnion(zdd, cuddT(P), cuddT(Q));
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ e = cuddZddUnion(zdd, cuddE(P), cuddE(Q));
+ if (e == NULL) {
+ Cudd_RecursiveDerefZdd(table, t);
+ return(NULL);
+ }
+ cuddRef(e);
+ res = cuddZddGetNode(zdd, P->index, t, e);
+ if (res == NULL) {
+ Cudd_RecursiveDerefZdd(table, t);
+ Cudd_RecursiveDerefZdd(table, e);
+ return(NULL);
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+ }
+
+ cuddCacheInsert2(table, cuddZddUnion, P, Q, res);
+
+ return(res);
+
+} /* end of cuddZddUnion */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddIntersect.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+cuddZddIntersect(
+ DdManager * zdd,
+ DdNode * P,
+ DdNode * Q)
+{
+ int p_top, q_top;
+ DdNode *empty = DD_ZERO(zdd), *t, *e, *res;
+ DdManager *table = zdd;
+
+ statLine(zdd);
+ if (P == empty)
+ return(empty);
+ if (Q == empty)
+ return(empty);
+ if (P == Q)
+ return(P);
+
+ /* Check cache. */
+ res = cuddCacheLookup2Zdd(table, cuddZddIntersect, P, Q);
+ if (res != NULL)
+ return(res);
+
+ if (cuddIsConstant(P))
+ p_top = P->index;
+ else
+ p_top = zdd->permZ[P->index];
+ if (cuddIsConstant(Q))
+ q_top = Q->index;
+ else
+ q_top = zdd->permZ[Q->index];
+ if (p_top < q_top) {
+ res = cuddZddIntersect(zdd, cuddE(P), Q);
+ if (res == NULL) return(NULL);
+ } else if (p_top > q_top) {
+ res = cuddZddIntersect(zdd, P, cuddE(Q));
+ if (res == NULL) return(NULL);
+ } else {
+ t = cuddZddIntersect(zdd, cuddT(P), cuddT(Q));
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ e = cuddZddIntersect(zdd, cuddE(P), cuddE(Q));
+ if (e == NULL) {
+ Cudd_RecursiveDerefZdd(table, t);
+ return(NULL);
+ }
+ cuddRef(e);
+ res = cuddZddGetNode(zdd, P->index, t, e);
+ if (res == NULL) {
+ Cudd_RecursiveDerefZdd(table, t);
+ Cudd_RecursiveDerefZdd(table, e);
+ return(NULL);
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+ }
+
+ cuddCacheInsert2(table, cuddZddIntersect, P, Q, res);
+
+ return(res);
+
+} /* end of cuddZddIntersect */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddDiff.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+cuddZddDiff(
+ DdManager * zdd,
+ DdNode * P,
+ DdNode * Q)
+{
+ int p_top, q_top;
+ DdNode *empty = DD_ZERO(zdd), *t, *e, *res;
+ DdManager *table = zdd;
+
+ statLine(zdd);
+ if (P == empty)
+ return(empty);
+ if (Q == empty)
+ return(P);
+ if (P == Q)
+ return(empty);
+
+ /* Check cache. The cache is shared by Cudd_zddDiffConst(). */
+ res = cuddCacheLookup2Zdd(table, cuddZddDiff, P, Q);
+ if (res != NULL && res != DD_NON_CONSTANT)
+ return(res);
+
+ if (cuddIsConstant(P))
+ p_top = P->index;
+ else
+ p_top = zdd->permZ[P->index];
+ if (cuddIsConstant(Q))
+ q_top = Q->index;
+ else
+ q_top = zdd->permZ[Q->index];
+ if (p_top < q_top) {
+ e = cuddZddDiff(zdd, cuddE(P), Q);
+ if (e == NULL) return(NULL);
+ cuddRef(e);
+ res = cuddZddGetNode(zdd, P->index, cuddT(P), e);
+ if (res == NULL) {
+ Cudd_RecursiveDerefZdd(table, e);
+ return(NULL);
+ }
+ cuddDeref(e);
+ } else if (p_top > q_top) {
+ res = cuddZddDiff(zdd, P, cuddE(Q));
+ if (res == NULL) return(NULL);
+ } else {
+ t = cuddZddDiff(zdd, cuddT(P), cuddT(Q));
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ e = cuddZddDiff(zdd, cuddE(P), cuddE(Q));
+ if (e == NULL) {
+ Cudd_RecursiveDerefZdd(table, t);
+ return(NULL);
+ }
+ cuddRef(e);
+ res = cuddZddGetNode(zdd, P->index, t, e);
+ if (res == NULL) {
+ Cudd_RecursiveDerefZdd(table, t);
+ Cudd_RecursiveDerefZdd(table, e);
+ return(NULL);
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+ }
+
+ cuddCacheInsert2(table, cuddZddDiff, P, Q, res);
+
+ return(res);
+
+} /* end of cuddZddDiff */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddChange.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+cuddZddChangeAux(
+ DdManager * zdd,
+ DdNode * P,
+ DdNode * zvar)
+{
+ int top_var, level;
+ DdNode *res, *t, *e;
+ DdNode *base = DD_ONE(zdd);
+ DdNode *empty = DD_ZERO(zdd);
+
+ statLine(zdd);
+ if (P == empty)
+ return(empty);
+ if (P == base)
+ return(zvar);
+
+ /* Check cache. */
+ res = cuddCacheLookup2Zdd(zdd, cuddZddChangeAux, P, zvar);
+ if (res != NULL)
+ return(res);
+
+ top_var = zdd->permZ[P->index];
+ level = zdd->permZ[zvar->index];
+
+ if (top_var > level) {
+ res = cuddZddGetNode(zdd, zvar->index, P, DD_ZERO(zdd));
+ if (res == NULL) return(NULL);
+ } else if (top_var == level) {
+ res = cuddZddGetNode(zdd, zvar->index, cuddE(P), cuddT(P));
+ if (res == NULL) return(NULL);
+ } else {
+ t = cuddZddChangeAux(zdd, cuddT(P), zvar);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ e = cuddZddChangeAux(zdd, cuddE(P), zvar);
+ if (e == NULL) {
+ Cudd_RecursiveDerefZdd(zdd, t);
+ return(NULL);
+ }
+ cuddRef(e);
+ res = cuddZddGetNode(zdd, P->index, t, e);
+ if (res == NULL) {
+ Cudd_RecursiveDerefZdd(zdd, t);
+ Cudd_RecursiveDerefZdd(zdd, e);
+ return(NULL);
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+ }
+
+ cuddCacheInsert2(zdd, cuddZddChangeAux, P, zvar, res);
+
+ return(res);
+
+} /* end of cuddZddChangeAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the positive cofactor of a ZDD w.r.t. a variable.]
+
+ Description [Computes the positive cofactor of a ZDD w.r.t. a
+ variable. In terms of combinations, the result is the set of all
+ combinations in which the variable is asserted. Returns a pointer to
+ the result if successful; NULL otherwise. cuddZddSubset1 performs
+ the same function as Cudd_zddSubset1, but does not restart if
+ reordering has taken place. Therefore it can be called from within a
+ recursive procedure.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddZddSubset0 Cudd_zddSubset1]
+
+******************************************************************************/
+DdNode *
+cuddZddSubset1(
+ DdManager * dd,
+ DdNode * P,
+ int var)
+{
+ DdNode *zvar, *r;
+ DdNode *base, *empty;
+
+ base = DD_ONE(dd);
+ empty = DD_ZERO(dd);
+
+ zvar = cuddUniqueInterZdd(dd, var, base, empty);
+ if (zvar == NULL) {
+ return(NULL);
+ } else {
+ cuddRef(zvar);
+ r = zdd_subset1_aux(dd, P, zvar);
+ if (r == NULL) {
+ Cudd_RecursiveDerefZdd(dd, zvar);
+ return(NULL);
+ }
+ cuddRef(r);
+ Cudd_RecursiveDerefZdd(dd, zvar);
+ }
+
+ cuddDeref(r);
+ return(r);
+
+} /* end of cuddZddSubset1 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes the negative cofactor of a ZDD w.r.t. a variable.]
+
+ Description [Computes the negative cofactor of a ZDD w.r.t. a
+ variable. In terms of combinations, the result is the set of all
+ combinations in which the variable is negated. Returns a pointer to
+ the result if successful; NULL otherwise. cuddZddSubset0 performs
+ the same function as Cudd_zddSubset0, but does not restart if
+ reordering has taken place. Therefore it can be called from within a
+ recursive procedure.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddZddSubset1 Cudd_zddSubset0]
+
+******************************************************************************/
+DdNode *
+cuddZddSubset0(
+ DdManager * dd,
+ DdNode * P,
+ int var)
+{
+ DdNode *zvar, *r;
+ DdNode *base, *empty;
+
+ base = DD_ONE(dd);
+ empty = DD_ZERO(dd);
+
+ zvar = cuddUniqueInterZdd(dd, var, base, empty);
+ if (zvar == NULL) {
+ return(NULL);
+ } else {
+ cuddRef(zvar);
+ r = zdd_subset0_aux(dd, P, zvar);
+ if (r == NULL) {
+ Cudd_RecursiveDerefZdd(dd, zvar);
+ return(NULL);
+ }
+ cuddRef(r);
+ Cudd_RecursiveDerefZdd(dd, zvar);
+ }
+
+ cuddDeref(r);
+ return(r);
+
+} /* end of cuddZddSubset0 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Substitutes a variable with its complement in a ZDD.]
+
+ Description [Substitutes a variable with its complement in a ZDD.
+ returns a pointer to the result if successful; NULL
+ otherwise. cuddZddChange performs the same function as
+ Cudd_zddChange, but does not restart if reordering has taken
+ place. Therefore it can be called from within a recursive
+ procedure.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddChange]
+
+******************************************************************************/
+DdNode *
+cuddZddChange(
+ DdManager * dd,
+ DdNode * P,
+ int var)
+{
+ DdNode *zvar, *res;
+
+ zvar = cuddUniqueInterZdd(dd, var, DD_ONE(dd), DD_ZERO(dd));
+ if (zvar == NULL) return(NULL);
+ cuddRef(zvar);
+
+ res = cuddZddChangeAux(dd, P, zvar);
+ if (res == NULL) {
+ Cudd_RecursiveDerefZdd(dd,zvar);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_RecursiveDerefZdd(dd,zvar);
+ cuddDeref(res);
+ return(res);
+
+} /* end of cuddZddChange */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddSubset1.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+zdd_subset1_aux(
+ DdManager * zdd,
+ DdNode * P,
+ DdNode * zvar)
+{
+ int top_var, level;
+ DdNode *res, *t, *e;
+ DdNode *base, *empty;
+
+ statLine(zdd);
+ base = DD_ONE(zdd);
+ empty = DD_ZERO(zdd);
+
+ /* Check cache. */
+ res = cuddCacheLookup2Zdd(zdd, zdd_subset1_aux, P, zvar);
+ if (res != NULL)
+ return(res);
+
+ if (cuddIsConstant(P)) {
+ res = empty;
+ cuddCacheInsert2(zdd, zdd_subset1_aux, P, zvar, res);
+ return(res);
+ }
+
+ top_var = zdd->permZ[P->index];
+ level = zdd->permZ[zvar->index];
+
+ if (top_var > level) {
+ res = empty;
+ } else if (top_var == level) {
+ res = cuddT(P);
+ } else {
+ t = zdd_subset1_aux(zdd, cuddT(P), zvar);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ e = zdd_subset1_aux(zdd, cuddE(P), zvar);
+ if (e == NULL) {
+ Cudd_RecursiveDerefZdd(zdd, t);
+ return(NULL);
+ }
+ cuddRef(e);
+ res = cuddZddGetNode(zdd, P->index, t, e);
+ if (res == NULL) {
+ Cudd_RecursiveDerefZdd(zdd, t);
+ Cudd_RecursiveDerefZdd(zdd, e);
+ return(NULL);
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+ }
+
+ cuddCacheInsert2(zdd, zdd_subset1_aux, P, zvar, res);
+
+ return(res);
+
+} /* end of zdd_subset1_aux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddSubset0.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static DdNode *
+zdd_subset0_aux(
+ DdManager * zdd,
+ DdNode * P,
+ DdNode * zvar)
+{
+ int top_var, level;
+ DdNode *res, *t, *e;
+ DdNode *base, *empty;
+
+ statLine(zdd);
+ base = DD_ONE(zdd);
+ empty = DD_ZERO(zdd);
+
+ /* Check cache. */
+ res = cuddCacheLookup2Zdd(zdd, zdd_subset0_aux, P, zvar);
+ if (res != NULL)
+ return(res);
+
+ if (cuddIsConstant(P)) {
+ res = P;
+ cuddCacheInsert2(zdd, zdd_subset0_aux, P, zvar, res);
+ return(res);
+ }
+
+ top_var = zdd->permZ[P->index];
+ level = zdd->permZ[zvar->index];
+
+ if (top_var > level) {
+ res = P;
+ }
+ else if (top_var == level) {
+ res = cuddE(P);
+ }
+ else {
+ t = zdd_subset0_aux(zdd, cuddT(P), zvar);
+ if (t == NULL) return(NULL);
+ cuddRef(t);
+ e = zdd_subset0_aux(zdd, cuddE(P), zvar);
+ if (e == NULL) {
+ Cudd_RecursiveDerefZdd(zdd, t);
+ return(NULL);
+ }
+ cuddRef(e);
+ res = cuddZddGetNode(zdd, P->index, t, e);
+ if (res == NULL) {
+ Cudd_RecursiveDerefZdd(zdd, t);
+ Cudd_RecursiveDerefZdd(zdd, e);
+ return(NULL);
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+ }
+
+ cuddCacheInsert2(zdd, zdd_subset0_aux, P, zvar, res);
+
+ return(res);
+
+} /* end of zdd_subset0_aux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Replaces variables with constants if possible (part of
+ canonical form).]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+zddVarToConst(
+ DdNode * f,
+ DdNode ** gp,
+ DdNode ** hp,
+ DdNode * base,
+ DdNode * empty)
+{
+ DdNode *g = *gp;
+ DdNode *h = *hp;
+
+ if (f == g) { /* ITE(F,F,H) = ITE(F,1,H) = F + H */
+ *gp = base;
+ }
+
+ if (f == h) { /* ITE(F,G,F) = ITE(F,G,0) = F * G */
+ *hp = empty;
+ }
+
+} /* end of zddVarToConst */
+
diff --git a/src/bdd/cudd/cuddZddSymm.c b/src/bdd/cudd/cuddZddSymm.c
new file mode 100644
index 00000000..c9ffaab4
--- /dev/null
+++ b/src/bdd/cudd/cuddZddSymm.c
@@ -0,0 +1,1677 @@
+/**CFile***********************************************************************
+
+ FileName [cuddZddSymm.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions for symmetry-based ZDD variable reordering.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_zddSymmProfile()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddZddSymmCheck()
+ <li> cuddZddSymmSifting()
+ <li> cuddZddSymmSiftingConv()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> cuddZddUniqueCompare()
+ <li> cuddZddSymmSiftingAux()
+ <li> cuddZddSymmSiftingConvAux()
+ <li> cuddZddSymmSifting_up()
+ <li> cuddZddSymmSifting_down()
+ <li> zdd_group_move()
+ <li> cuddZddSymmSiftingBackward()
+ <li> zdd_group_move_backward()
+ </ul>
+ ]
+
+ SeeAlso [cuddSymmetry.c]
+
+ Author [Hyong-Kyoon Shin, In-Ho Moon]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define ZDD_MV_OOM (Move *)1
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddZddSymm.c,v 1.1.1.1 2003/02/24 22:23:54 wjiang Exp $";
+#endif
+
+extern int *zdd_entry;
+
+extern int zddTotalNumberSwapping;
+
+static DdNode *empty;
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int cuddZddSymmSiftingAux ARGS((DdManager *table, int x, int x_low, int x_high));
+static int cuddZddSymmSiftingConvAux ARGS((DdManager *table, int x, int x_low, int x_high));
+static Move * cuddZddSymmSifting_up ARGS((DdManager *table, int x, int x_low, int initial_size));
+static Move * cuddZddSymmSifting_down ARGS((DdManager *table, int x, int x_high, int initial_size));
+static int cuddZddSymmSiftingBackward ARGS((DdManager *table, Move *moves, int size));
+static int zdd_group_move ARGS((DdManager *table, int x, int y, Move **moves));
+static int zdd_group_move_backward ARGS((DdManager *table, int x, int y));
+static void cuddZddSymmSummary ARGS((DdManager *table, int lower, int upper, int *symvars, int *symgroups));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints statistics on symmetric ZDD variables.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+Cudd_zddSymmProfile(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int i, x, gbot;
+ int TotalSymm = 0;
+ int TotalSymmGroups = 0;
+ int nvars;
+
+ nvars = table->sizeZ;
+
+ for (i = lower; i < upper; i++) {
+ if (table->subtableZ[i].next != (unsigned) i) {
+ x = i;
+ (void) fprintf(table->out,"Group:");
+ do {
+ (void) fprintf(table->out," %d", table->invpermZ[x]);
+ TotalSymm++;
+ gbot = x;
+ x = table->subtableZ[x].next;
+ } while (x != i);
+ TotalSymmGroups++;
+#ifdef DD_DEBUG
+ assert(table->subtableZ[gbot].next == (unsigned) i);
+#endif
+ i = gbot;
+ (void) fprintf(table->out,"\n");
+ }
+ }
+ (void) fprintf(table->out,"Total Symmetric = %d\n", TotalSymm);
+ (void) fprintf(table->out,"Total Groups = %d\n", TotalSymmGroups);
+
+} /* end of Cudd_zddSymmProfile */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks for symmetry of x and y.]
+
+ Description [Checks for symmetry of x and y. Ignores projection
+ functions, unless they are isolated. Returns 1 in case of
+ symmetry; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddZddSymmCheck(
+ DdManager * table,
+ int x,
+ int y)
+{
+ int i;
+ DdNode *f, *f0, *f1, *f01, *f00, *f11, *f10;
+ int yindex;
+ int xsymmy = 1;
+ int xsymmyp = 1;
+ int arccount = 0;
+ int TotalRefCount = 0;
+ int symm_found;
+
+ empty = table->zero;
+
+ yindex = table->invpermZ[y];
+ for (i = table->subtableZ[x].slots - 1; i >= 0; i--) {
+ f = table->subtableZ[x].nodelist[i];
+ while (f != NULL) {
+ /* Find f1, f0, f11, f10, f01, f00 */
+ f1 = cuddT(f);
+ f0 = cuddE(f);
+ if ((int) f1->index == yindex) {
+ f11 = cuddT(f1);
+ f10 = cuddE(f1);
+ if (f10 != empty)
+ arccount++;
+ } else {
+ if ((int) f0->index != yindex) {
+ return(0); /* f bypasses layer y */
+ }
+ f11 = empty;
+ f10 = f1;
+ }
+ if ((int) f0->index == yindex) {
+ f01 = cuddT(f0);
+ f00 = cuddE(f0);
+ if (f00 != empty)
+ arccount++;
+ } else {
+ f01 = empty;
+ f00 = f0;
+ }
+ if (f01 != f10)
+ xsymmy = 0;
+ if (f11 != f00)
+ xsymmyp = 0;
+ if ((xsymmy == 0) && (xsymmyp == 0))
+ return(0);
+
+ f = f->next;
+ } /* for each element of the collision list */
+ } /* for each slot of the subtable */
+
+ /* Calculate the total reference counts of y
+ ** whose else arc is not empty.
+ */
+ for (i = table->subtableZ[y].slots - 1; i >= 0; i--) {
+ f = table->subtableZ[y].nodelist[i];
+ while (f != NIL(DdNode)) {
+ if (cuddE(f) != empty)
+ TotalRefCount += f->ref;
+ f = f->next;
+ }
+ }
+
+ symm_found = (arccount == TotalRefCount);
+#if defined(DD_DEBUG) && defined(DD_VERBOSE)
+ if (symm_found) {
+ int xindex = table->invpermZ[x];
+ (void) fprintf(table->out,
+ "Found symmetry! x =%d\ty = %d\tPos(%d,%d)\n",
+ xindex,yindex,x,y);
+ }
+#endif
+
+ return(symm_found);
+
+} /* end cuddZddSymmCheck */
+
+
+/**Function********************************************************************
+
+ Synopsis [Symmetric sifting algorithm for ZDDs.]
+
+ Description [Symmetric sifting algorithm.
+ Assumes that no dead nodes are present.
+ <ol>
+ <li> Order all the variables according to the number of entries in
+ each unique subtable.
+ <li> Sift the variable up and down, remembering each time the total
+ size of the ZDD heap and grouping variables that are symmetric.
+ <li> Select the best permutation.
+ <li> Repeat 3 and 4 for all variables.
+ </ol>
+ Returns 1 plus the number of symmetric variables if successful; 0
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddZddSymmSiftingConv]
+
+******************************************************************************/
+int
+cuddZddSymmSifting(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int i;
+ int *var;
+ int nvars;
+ int x;
+ int result;
+ int symvars;
+ int symgroups;
+ int iteration;
+#ifdef DD_STATS
+ int previousSize;
+#endif
+
+ nvars = table->sizeZ;
+
+ /* Find order in which to sift variables. */
+ var = NULL;
+ zdd_entry = ALLOC(int, nvars);
+ if (zdd_entry == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto cuddZddSymmSiftingOutOfMem;
+ }
+ var = ALLOC(int, nvars);
+ if (var == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto cuddZddSymmSiftingOutOfMem;
+ }
+
+ for (i = 0; i < nvars; i++) {
+ x = table->permZ[i];
+ zdd_entry[i] = table->subtableZ[x].keys;
+ var[i] = i;
+ }
+
+ qsort((void *)var, nvars, sizeof(int), (int (*)(const void *, const void *))cuddZddUniqueCompare);
+
+ /* Initialize the symmetry of each subtable to itself. */
+ for (i = lower; i <= upper; i++)
+ table->subtableZ[i].next = i;
+
+ iteration = ddMin(table->siftMaxVar, nvars);
+ for (i = 0; i < iteration; i++) {
+ if (zddTotalNumberSwapping >= table->siftMaxSwap)
+ break;
+ x = table->permZ[var[i]];
+#ifdef DD_STATS
+ previousSize = table->keysZ;
+#endif
+ if (x < lower || x > upper) continue;
+ if (table->subtableZ[x].next == (unsigned) x) {
+ result = cuddZddSymmSiftingAux(table, x, lower, upper);
+ if (!result)
+ goto cuddZddSymmSiftingOutOfMem;
+#ifdef DD_STATS
+ if (table->keysZ < (unsigned) previousSize) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keysZ > (unsigned) previousSize) {
+ (void) fprintf(table->out,"+");
+#ifdef DD_VERBOSE
+ (void) fprintf(table->out,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keysZ, var[i]);
+#endif
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+ }
+
+ FREE(var);
+ FREE(zdd_entry);
+
+ cuddZddSymmSummary(table, lower, upper, &symvars, &symgroups);
+
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\n#:S_SIFTING %8d: symmetric variables\n",symvars);
+ (void) fprintf(table->out,"#:G_SIFTING %8d: symmetric groups\n",symgroups);
+#endif
+
+ return(1+symvars);
+
+cuddZddSymmSiftingOutOfMem:
+
+ if (zdd_entry != NULL)
+ FREE(zdd_entry);
+ if (var != NULL)
+ FREE(var);
+
+ return(0);
+
+} /* end of cuddZddSymmSifting */
+
+
+/**Function********************************************************************
+
+ Synopsis [Symmetric sifting to convergence algorithm for ZDDs.]
+
+ Description [Symmetric sifting to convergence algorithm for ZDDs.
+ Assumes that no dead nodes are present.
+ <ol>
+ <li> Order all the variables according to the number of entries in
+ each unique subtable.
+ <li> Sift the variable up and down, remembering each time the total
+ size of the ZDD heap and grouping variables that are symmetric.
+ <li> Select the best permutation.
+ <li> Repeat 3 and 4 for all variables.
+ <li> Repeat 1-4 until no further improvement.
+ </ol>
+ Returns 1 plus the number of symmetric variables if successful; 0
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddZddSymmSifting]
+
+******************************************************************************/
+int
+cuddZddSymmSiftingConv(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int i;
+ int *var;
+ int nvars;
+ int initialSize;
+ int x;
+ int result;
+ int symvars;
+ int symgroups;
+ int classes;
+ int iteration;
+#ifdef DD_STATS
+ int previousSize;
+#endif
+
+ initialSize = table->keysZ;
+
+ nvars = table->sizeZ;
+
+ /* Find order in which to sift variables. */
+ var = NULL;
+ zdd_entry = ALLOC(int, nvars);
+ if (zdd_entry == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto cuddZddSymmSiftingConvOutOfMem;
+ }
+ var = ALLOC(int, nvars);
+ if (var == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto cuddZddSymmSiftingConvOutOfMem;
+ }
+
+ for (i = 0; i < nvars; i++) {
+ x = table->permZ[i];
+ zdd_entry[i] = table->subtableZ[x].keys;
+ var[i] = i;
+ }
+
+ qsort((void *)var, nvars, sizeof(int), (int (*)(const void *, const void *))cuddZddUniqueCompare);
+
+ /* Initialize the symmetry of each subtable to itself
+ ** for first pass of converging symmetric sifting.
+ */
+ for (i = lower; i <= upper; i++)
+ table->subtableZ[i].next = i;
+
+ iteration = ddMin(table->siftMaxVar, table->sizeZ);
+ for (i = 0; i < iteration; i++) {
+ if (zddTotalNumberSwapping >= table->siftMaxSwap)
+ break;
+ x = table->permZ[var[i]];
+ if (x < lower || x > upper) continue;
+ /* Only sift if not in symmetry group already. */
+ if (table->subtableZ[x].next == (unsigned) x) {
+#ifdef DD_STATS
+ previousSize = table->keysZ;
+#endif
+ result = cuddZddSymmSiftingAux(table, x, lower, upper);
+ if (!result)
+ goto cuddZddSymmSiftingConvOutOfMem;
+#ifdef DD_STATS
+ if (table->keysZ < (unsigned) previousSize) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keysZ > (unsigned) previousSize) {
+ (void) fprintf(table->out,"+");
+#ifdef DD_VERBOSE
+ (void) fprintf(table->out,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keysZ, var[i]);
+#endif
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+ }
+
+ /* Sifting now until convergence. */
+ while ((unsigned) initialSize > table->keysZ) {
+ initialSize = table->keysZ;
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\n");
+#endif
+ /* Here we consider only one representative for each symmetry class. */
+ for (x = lower, classes = 0; x <= upper; x++, classes++) {
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ /* Here x is the largest index in a group.
+ ** Groups consists of adjacent variables.
+ ** Hence, the next increment of x will move it to a new group.
+ */
+ i = table->invpermZ[x];
+ zdd_entry[i] = table->subtableZ[x].keys;
+ var[classes] = i;
+ }
+
+ qsort((void *)var,classes,sizeof(int),(int (*)(const void *, const void *))cuddZddUniqueCompare);
+
+ /* Now sift. */
+ iteration = ddMin(table->siftMaxVar, nvars);
+ for (i = 0; i < iteration; i++) {
+ if (zddTotalNumberSwapping >= table->siftMaxSwap)
+ break;
+ x = table->permZ[var[i]];
+ if ((unsigned) x >= table->subtableZ[x].next) {
+#ifdef DD_STATS
+ previousSize = table->keysZ;
+#endif
+ result = cuddZddSymmSiftingConvAux(table, x, lower, upper);
+ if (!result)
+ goto cuddZddSymmSiftingConvOutOfMem;
+#ifdef DD_STATS
+ if (table->keysZ < (unsigned) previousSize) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keysZ > (unsigned) previousSize) {
+ (void) fprintf(table->out,"+");
+#ifdef DD_VERBOSE
+ (void) fprintf(table->out,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keysZ, var[i]);
+#endif
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+ } /* for */
+ }
+
+ cuddZddSymmSummary(table, lower, upper, &symvars, &symgroups);
+
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\n#:S_SIFTING %8d: symmetric variables\n",
+ symvars);
+ (void) fprintf(table->out,"#:G_SIFTING %8d: symmetric groups\n",
+ symgroups);
+#endif
+
+ FREE(var);
+ FREE(zdd_entry);
+
+ return(1+symvars);
+
+cuddZddSymmSiftingConvOutOfMem:
+
+ if (zdd_entry != NULL)
+ FREE(zdd_entry);
+ if (var != NULL)
+ FREE(var);
+
+ return(0);
+
+} /* end of cuddZddSymmSiftingConv */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Given x_low <= x <= x_high moves x up and down between the
+ boundaries.]
+
+ Description [Given x_low <= x <= x_high moves x up and down between the
+ boundaries. Finds the best position and does the required changes.
+ Assumes that x is not part of a symmetry group. Returns 1 if
+ successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddZddSymmSiftingAux(
+ DdManager * table,
+ int x,
+ int x_low,
+ int x_high)
+{
+ Move *move;
+ Move *move_up; /* list of up move */
+ Move *move_down; /* list of down move */
+ int initial_size;
+ int result;
+ int i;
+ int topbot; /* index to either top or bottom of symmetry group */
+ int init_group_size, final_group_size;
+
+ initial_size = table->keysZ;
+
+ move_down = NULL;
+ move_up = NULL;
+
+ /* Look for consecutive symmetries above x. */
+ for (i = x; i > x_low; i--) {
+ if (!cuddZddSymmCheck(table, i - 1, i))
+ break;
+ /* find top of i-1's symmetry */
+ topbot = table->subtableZ[i - 1].next;
+ table->subtableZ[i - 1].next = i;
+ table->subtableZ[x].next = topbot;
+ /* x is bottom of group so its symmetry is top of i-1's
+ group */
+ i = topbot + 1; /* add 1 for i--, new i is top of symm group */
+ }
+ /* Look for consecutive symmetries below x. */
+ for (i = x; i < x_high; i++) {
+ if (!cuddZddSymmCheck(table, i, i + 1))
+ break;
+ /* find bottom of i+1's symm group */
+ topbot = i + 1;
+ while ((unsigned) topbot < table->subtableZ[topbot].next)
+ topbot = table->subtableZ[topbot].next;
+
+ table->subtableZ[topbot].next = table->subtableZ[i].next;
+ table->subtableZ[i].next = i + 1;
+ i = topbot - 1; /* add 1 for i++,
+ new i is bottom of symm group */
+ }
+
+ /* Now x maybe in the middle of a symmetry group. */
+ if (x == x_low) { /* Sift down */
+ /* Find bottom of x's symm group */
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+
+ i = table->subtableZ[x].next;
+ init_group_size = x - i + 1;
+
+ move_down = cuddZddSymmSifting_down(table, x, x_high,
+ initial_size);
+ /* after that point x --> x_high, unless early term */
+ if (move_down == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingAuxOutOfMem;
+
+ if (move_down == NULL ||
+ table->subtableZ[move_down->y].next != move_down->y) {
+ /* symmetry detected may have to make another complete
+ pass */
+ if (move_down != NULL)
+ x = move_down->y;
+ else
+ x = table->subtableZ[x].next;
+ i = x;
+ while ((unsigned) i < table->subtableZ[i].next) {
+ i = table->subtableZ[i].next;
+ }
+ final_group_size = i - x + 1;
+
+ if (init_group_size == final_group_size) {
+ /* No new symmetry groups detected,
+ return to best position */
+ result = cuddZddSymmSiftingBackward(table,
+ move_down, initial_size);
+ }
+ else {
+ initial_size = table->keysZ;
+ move_up = cuddZddSymmSifting_up(table, x, x_low,
+ initial_size);
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ }
+ }
+ else {
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ /* move backward and stop at best position */
+ }
+ if (!result)
+ goto cuddZddSymmSiftingAuxOutOfMem;
+ }
+ else if (x == x_high) { /* Sift up */
+ /* Find top of x's symm group */
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ x = table->subtableZ[x].next;
+
+ i = x;
+ while ((unsigned) i < table->subtableZ[i].next) {
+ i = table->subtableZ[i].next;
+ }
+ init_group_size = i - x + 1;
+
+ move_up = cuddZddSymmSifting_up(table, x, x_low, initial_size);
+ /* after that point x --> x_low, unless early term */
+ if (move_up == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingAuxOutOfMem;
+
+ if (move_up == NULL ||
+ table->subtableZ[move_up->x].next != move_up->x) {
+ /* symmetry detected may have to make another complete
+ pass */
+ if (move_up != NULL)
+ x = move_up->x;
+ else {
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ }
+ i = table->subtableZ[x].next;
+ final_group_size = x - i + 1;
+
+ if (init_group_size == final_group_size) {
+ /* No new symmetry groups detected,
+ return to best position */
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ }
+ else {
+ initial_size = table->keysZ;
+ move_down = cuddZddSymmSifting_down(table, x, x_high,
+ initial_size);
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ }
+ }
+ else {
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ /* move backward and stop at best position */
+ }
+ if (!result)
+ goto cuddZddSymmSiftingAuxOutOfMem;
+ }
+ else if ((x - x_low) > (x_high - x)) { /* must go down first:
+ shorter */
+ /* Find bottom of x's symm group */
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+
+ move_down = cuddZddSymmSifting_down(table, x, x_high,
+ initial_size);
+ /* after that point x --> x_high, unless early term */
+ if (move_down == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingAuxOutOfMem;
+
+ if (move_down != NULL) {
+ x = move_down->y;
+ }
+ else {
+ x = table->subtableZ[x].next;
+ }
+ i = x;
+ while ((unsigned) i < table->subtableZ[i].next) {
+ i = table->subtableZ[i].next;
+ }
+ init_group_size = i - x + 1;
+
+ move_up = cuddZddSymmSifting_up(table, x, x_low, initial_size);
+ if (move_up == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingAuxOutOfMem;
+
+ if (move_up == NULL ||
+ table->subtableZ[move_up->x].next != move_up->x) {
+ /* symmetry detected may have to make another complete
+ pass */
+ if (move_up != NULL) {
+ x = move_up->x;
+ }
+ else {
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ }
+ i = table->subtableZ[x].next;
+ final_group_size = x - i + 1;
+
+ if (init_group_size == final_group_size) {
+ /* No new symmetry groups detected,
+ return to best position */
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ }
+ else {
+ while (move_down != NULL) {
+ move = move_down->next;
+ cuddDeallocNode(table, (DdNode *)move_down);
+ move_down = move;
+ }
+ initial_size = table->keysZ;
+ move_down = cuddZddSymmSifting_down(table, x, x_high,
+ initial_size);
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ }
+ }
+ else {
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ /* move backward and stop at best position */
+ }
+ if (!result)
+ goto cuddZddSymmSiftingAuxOutOfMem;
+ }
+ else { /* moving up first:shorter */
+ /* Find top of x's symmetry group */
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ x = table->subtableZ[x].next;
+
+ move_up = cuddZddSymmSifting_up(table, x, x_low, initial_size);
+ /* after that point x --> x_high, unless early term */
+ if (move_up == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingAuxOutOfMem;
+
+ if (move_up != NULL) {
+ x = move_up->x;
+ }
+ else {
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ }
+ i = table->subtableZ[x].next;
+ init_group_size = x - i + 1;
+
+ move_down = cuddZddSymmSifting_down(table, x, x_high,
+ initial_size);
+ if (move_down == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingAuxOutOfMem;
+
+ if (move_down == NULL ||
+ table->subtableZ[move_down->y].next != move_down->y) {
+ /* symmetry detected may have to make another complete
+ pass */
+ if (move_down != NULL) {
+ x = move_down->y;
+ }
+ else {
+ x = table->subtableZ[x].next;
+ }
+ i = x;
+ while ((unsigned) i < table->subtableZ[i].next) {
+ i = table->subtableZ[i].next;
+ }
+ final_group_size = i - x + 1;
+
+ if (init_group_size == final_group_size) {
+ /* No new symmetries detected,
+ go back to best position */
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ }
+ else {
+ while (move_up != NULL) {
+ move = move_up->next;
+ cuddDeallocNode(table, (DdNode *)move_up);
+ move_up = move;
+ }
+ initial_size = table->keysZ;
+ move_up = cuddZddSymmSifting_up(table, x, x_low,
+ initial_size);
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ }
+ }
+ else {
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ /* move backward and stop at best position */
+ }
+ if (!result)
+ goto cuddZddSymmSiftingAuxOutOfMem;
+ }
+
+ while (move_down != NULL) {
+ move = move_down->next;
+ cuddDeallocNode(table, (DdNode *)move_down);
+ move_down = move;
+ }
+ while (move_up != NULL) {
+ move = move_up->next;
+ cuddDeallocNode(table, (DdNode *)move_up);
+ move_up = move;
+ }
+
+ return(1);
+
+cuddZddSymmSiftingAuxOutOfMem:
+ if (move_down != ZDD_MV_OOM) {
+ while (move_down != NULL) {
+ move = move_down->next;
+ cuddDeallocNode(table, (DdNode *)move_down);
+ move_down = move;
+ }
+ }
+ if (move_up != ZDD_MV_OOM) {
+ while (move_up != NULL) {
+ move = move_up->next;
+ cuddDeallocNode(table, (DdNode *)move_up);
+ move_up = move;
+ }
+ }
+
+ return(0);
+
+} /* end of cuddZddSymmSiftingAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given x_low <= x <= x_high moves x up and down between the
+ boundaries.]
+
+ Description [Given x_low <= x <= x_high moves x up and down between the
+ boundaries. Finds the best position and does the required changes.
+ Assumes that x is either an isolated variable, or it is the bottom of
+ a symmetry group. All symmetries may not have been found, because of
+ exceeded growth limit. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddZddSymmSiftingConvAux(
+ DdManager * table,
+ int x,
+ int x_low,
+ int x_high)
+{
+ Move *move;
+ Move *move_up; /* list of up move */
+ Move *move_down; /* list of down move */
+ int initial_size;
+ int result;
+ int i;
+ int init_group_size, final_group_size;
+
+ initial_size = table->keysZ;
+
+ move_down = NULL;
+ move_up = NULL;
+
+ if (x == x_low) { /* Sift down */
+ i = table->subtableZ[x].next;
+ init_group_size = x - i + 1;
+
+ move_down = cuddZddSymmSifting_down(table, x, x_high,
+ initial_size);
+ /* after that point x --> x_high, unless early term */
+ if (move_down == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingConvAuxOutOfMem;
+
+ if (move_down == NULL ||
+ table->subtableZ[move_down->y].next != move_down->y) {
+ /* symmetry detected may have to make another complete
+ pass */
+ if (move_down != NULL)
+ x = move_down->y;
+ else {
+ while ((unsigned) x < table->subtableZ[x].next);
+ x = table->subtableZ[x].next;
+ x = table->subtableZ[x].next;
+ }
+ i = x;
+ while ((unsigned) i < table->subtableZ[i].next) {
+ i = table->subtableZ[i].next;
+ }
+ final_group_size = i - x + 1;
+
+ if (init_group_size == final_group_size) {
+ /* No new symmetries detected,
+ go back to best position */
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ }
+ else {
+ initial_size = table->keysZ;
+ move_up = cuddZddSymmSifting_up(table, x, x_low,
+ initial_size);
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ }
+ }
+ else {
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ /* move backward and stop at best position */
+ }
+ if (!result)
+ goto cuddZddSymmSiftingConvAuxOutOfMem;
+ }
+ else if (x == x_high) { /* Sift up */
+ /* Find top of x's symm group */
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ x = table->subtableZ[x].next;
+
+ i = x;
+ while ((unsigned) i < table->subtableZ[i].next) {
+ i = table->subtableZ[i].next;
+ }
+ init_group_size = i - x + 1;
+
+ move_up = cuddZddSymmSifting_up(table, x, x_low, initial_size);
+ /* after that point x --> x_low, unless early term */
+ if (move_up == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingConvAuxOutOfMem;
+
+ if (move_up == NULL ||
+ table->subtableZ[move_up->x].next != move_up->x) {
+ /* symmetry detected may have to make another complete
+ pass */
+ if (move_up != NULL)
+ x = move_up->x;
+ else {
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ }
+ i = table->subtableZ[x].next;
+ final_group_size = x - i + 1;
+
+ if (init_group_size == final_group_size) {
+ /* No new symmetry groups detected,
+ return to best position */
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ }
+ else {
+ initial_size = table->keysZ;
+ move_down = cuddZddSymmSifting_down(table, x, x_high,
+ initial_size);
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ }
+ }
+ else {
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ /* move backward and stop at best position */
+ }
+ if (!result)
+ goto cuddZddSymmSiftingConvAuxOutOfMem;
+ }
+ else if ((x - x_low) > (x_high - x)) { /* must go down first:
+ shorter */
+ move_down = cuddZddSymmSifting_down(table, x, x_high,
+ initial_size);
+ /* after that point x --> x_high */
+ if (move_down == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingConvAuxOutOfMem;
+
+ if (move_down != NULL) {
+ x = move_down->y;
+ }
+ else {
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ x = table->subtableZ[x].next;
+ }
+ i = x;
+ while ((unsigned) i < table->subtableZ[i].next) {
+ i = table->subtableZ[i].next;
+ }
+ init_group_size = i - x + 1;
+
+ move_up = cuddZddSymmSifting_up(table, x, x_low, initial_size);
+ if (move_up == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingConvAuxOutOfMem;
+
+ if (move_up == NULL ||
+ table->subtableZ[move_up->x].next != move_up->x) {
+ /* symmetry detected may have to make another complete
+ pass */
+ if (move_up != NULL) {
+ x = move_up->x;
+ }
+ else {
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ }
+ i = table->subtableZ[x].next;
+ final_group_size = x - i + 1;
+
+ if (init_group_size == final_group_size) {
+ /* No new symmetry groups detected,
+ return to best position */
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ }
+ else {
+ while (move_down != NULL) {
+ move = move_down->next;
+ cuddDeallocNode(table, (DdNode *)move_down);
+ move_down = move;
+ }
+ initial_size = table->keysZ;
+ move_down = cuddZddSymmSifting_down(table, x, x_high,
+ initial_size);
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ }
+ }
+ else {
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ /* move backward and stop at best position */
+ }
+ if (!result)
+ goto cuddZddSymmSiftingConvAuxOutOfMem;
+ }
+ else { /* moving up first:shorter */
+ /* Find top of x's symmetry group */
+ x = table->subtableZ[x].next;
+
+ move_up = cuddZddSymmSifting_up(table, x, x_low, initial_size);
+ /* after that point x --> x_high, unless early term */
+ if (move_up == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingConvAuxOutOfMem;
+
+ if (move_up != NULL) {
+ x = move_up->x;
+ }
+ else {
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ }
+ i = table->subtableZ[x].next;
+ init_group_size = x - i + 1;
+
+ move_down = cuddZddSymmSifting_down(table, x, x_high,
+ initial_size);
+ if (move_down == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingConvAuxOutOfMem;
+
+ if (move_down == NULL ||
+ table->subtableZ[move_down->y].next != move_down->y) {
+ /* symmetry detected may have to make another complete
+ pass */
+ if (move_down != NULL) {
+ x = move_down->y;
+ }
+ else {
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ x = table->subtableZ[x].next;
+ }
+ i = x;
+ while ((unsigned) i < table->subtableZ[i].next) {
+ i = table->subtableZ[i].next;
+ }
+ final_group_size = i - x + 1;
+
+ if (init_group_size == final_group_size) {
+ /* No new symmetries detected,
+ go back to best position */
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ }
+ else {
+ while (move_up != NULL) {
+ move = move_up->next;
+ cuddDeallocNode(table, (DdNode *)move_up);
+ move_up = move;
+ }
+ initial_size = table->keysZ;
+ move_up = cuddZddSymmSifting_up(table, x, x_low,
+ initial_size);
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ }
+ }
+ else {
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ /* move backward and stop at best position */
+ }
+ if (!result)
+ goto cuddZddSymmSiftingConvAuxOutOfMem;
+ }
+
+ while (move_down != NULL) {
+ move = move_down->next;
+ cuddDeallocNode(table, (DdNode *)move_down);
+ move_down = move;
+ }
+ while (move_up != NULL) {
+ move = move_up->next;
+ cuddDeallocNode(table, (DdNode *)move_up);
+ move_up = move;
+ }
+
+ return(1);
+
+cuddZddSymmSiftingConvAuxOutOfMem:
+ if (move_down != ZDD_MV_OOM) {
+ while (move_down != NULL) {
+ move = move_down->next;
+ cuddDeallocNode(table, (DdNode *)move_down);
+ move_down = move;
+ }
+ }
+ if (move_up != ZDD_MV_OOM) {
+ while (move_up != NULL) {
+ move = move_up->next;
+ cuddDeallocNode(table, (DdNode *)move_up);
+ move_up = move;
+ }
+ }
+
+ return(0);
+
+} /* end of cuddZddSymmSiftingConvAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Moves x up until either it reaches the bound (x_low) or
+ the size of the ZDD heap increases too much.]
+
+ Description [Moves x up until either it reaches the bound (x_low) or
+ the size of the ZDD heap increases too much. Assumes that x is the top
+ of a symmetry group. Checks x for symmetry to the adjacent
+ variables. If symmetry is found, the symmetry group of x is merged
+ with the symmetry group of the other variable. Returns the set of
+ moves in case of success; ZDD_MV_OOM if memory is full.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static Move *
+cuddZddSymmSifting_up(
+ DdManager * table,
+ int x,
+ int x_low,
+ int initial_size)
+{
+ Move *moves;
+ Move *move;
+ int y;
+ int size;
+ int limit_size = initial_size;
+ int i, gytop;
+
+ moves = NULL;
+ y = cuddZddNextLow(table, x);
+ while (y >= x_low) {
+ gytop = table->subtableZ[y].next;
+ if (cuddZddSymmCheck(table, y, x)) {
+ /* Symmetry found, attach symm groups */
+ table->subtableZ[y].next = x;
+ i = table->subtableZ[x].next;
+ while (table->subtableZ[i].next != (unsigned) x)
+ i = table->subtableZ[i].next;
+ table->subtableZ[i].next = gytop;
+ }
+ else if ((table->subtableZ[x].next == (unsigned) x) &&
+ (table->subtableZ[y].next == (unsigned) y)) {
+ /* x and y have self symmetry */
+ size = cuddZddSwapInPlace(table, y, x);
+ if (size == 0)
+ goto cuddZddSymmSifting_upOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto cuddZddSymmSifting_upOutOfMem;
+ move->x = y;
+ move->y = x;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ if ((double)size >
+ (double)limit_size * table->maxGrowth)
+ return(moves);
+ if (size < limit_size)
+ limit_size = size;
+ }
+ else { /* Group move */
+ size = zdd_group_move(table, y, x, &moves);
+ if ((double)size >
+ (double)limit_size * table->maxGrowth)
+ return(moves);
+ if (size < limit_size)
+ limit_size = size;
+ }
+ x = gytop;
+ y = cuddZddNextLow(table, x);
+ }
+
+ return(moves);
+
+cuddZddSymmSifting_upOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *)moves);
+ moves = move;
+ }
+ return(ZDD_MV_OOM);
+
+} /* end of cuddZddSymmSifting_up */
+
+
+/**Function********************************************************************
+
+ Synopsis [Moves x down until either it reaches the bound (x_high) or
+ the size of the ZDD heap increases too much.]
+
+ Description [Moves x down until either it reaches the bound (x_high)
+ or the size of the ZDD heap increases too much. Assumes that x is the
+ bottom of a symmetry group. Checks x for symmetry to the adjacent
+ variables. If symmetry is found, the symmetry group of x is merged
+ with the symmetry group of the other variable. Returns the set of
+ moves in case of success; ZDD_MV_OOM if memory is full.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static Move *
+cuddZddSymmSifting_down(
+ DdManager * table,
+ int x,
+ int x_high,
+ int initial_size)
+{
+ Move *moves;
+ Move *move;
+ int y;
+ int size;
+ int limit_size = initial_size;
+ int i, gxtop, gybot;
+
+ moves = NULL;
+ y = cuddZddNextHigh(table, x);
+ while (y <= x_high) {
+ gybot = table->subtableZ[y].next;
+ while (table->subtableZ[gybot].next != (unsigned) y)
+ gybot = table->subtableZ[gybot].next;
+ if (cuddZddSymmCheck(table, x, y)) {
+ /* Symmetry found, attach symm groups */
+ gxtop = table->subtableZ[x].next;
+ table->subtableZ[x].next = y;
+ i = table->subtableZ[y].next;
+ while (table->subtableZ[i].next != (unsigned) y)
+ i = table->subtableZ[i].next;
+ table->subtableZ[i].next = gxtop;
+ }
+ else if ((table->subtableZ[x].next == (unsigned) x) &&
+ (table->subtableZ[y].next == (unsigned) y)) {
+ /* x and y have self symmetry */
+ size = cuddZddSwapInPlace(table, x, y);
+ if (size == 0)
+ goto cuddZddSymmSifting_downOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto cuddZddSymmSifting_downOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ if ((double)size >
+ (double)limit_size * table->maxGrowth)
+ return(moves);
+ if (size < limit_size)
+ limit_size = size;
+ x = y;
+ y = cuddZddNextHigh(table, x);
+ }
+ else { /* Group move */
+ size = zdd_group_move(table, x, y, &moves);
+ if ((double)size >
+ (double)limit_size * table->maxGrowth)
+ return(moves);
+ if (size < limit_size)
+ limit_size = size;
+ }
+ x = gybot;
+ y = cuddZddNextHigh(table, x);
+ }
+
+ return(moves);
+
+cuddZddSymmSifting_downOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *)moves);
+ moves = move;
+ }
+ return(ZDD_MV_OOM);
+
+} /* end of cuddZddSymmSifting_down */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given a set of moves, returns the ZDD heap to the position
+ giving the minimum size.]
+
+ Description [Given a set of moves, returns the ZDD heap to the
+ position giving the minimum size. In case of ties, returns to the
+ closest position giving the minimum size. Returns 1 in case of
+ success; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddZddSymmSiftingBackward(
+ DdManager * table,
+ Move * moves,
+ int size)
+{
+ int i;
+ int i_best;
+ Move *move;
+ int res;
+
+ i_best = -1;
+ for (move = moves, i = 0; move != NULL; move = move->next, i++) {
+ if (move->size < size) {
+ i_best = i;
+ size = move->size;
+ }
+ }
+
+ for (move = moves, i = 0; move != NULL; move = move->next, i++) {
+ if (i == i_best) break;
+ if ((table->subtableZ[move->x].next == move->x) &&
+ (table->subtableZ[move->y].next == move->y)) {
+ res = cuddZddSwapInPlace(table, move->x, move->y);
+ if (!res) return(0);
+ }
+ else { /* Group move necessary */
+ res = zdd_group_move_backward(table, move->x, move->y);
+ }
+ if (i_best == -1 && res == size)
+ break;
+ }
+
+ return(1);
+
+} /* end of cuddZddSymmSiftingBackward */
+
+
+/**Function********************************************************************
+
+ Synopsis [Swaps two groups.]
+
+ Description [Swaps two groups. x is assumed to be the bottom variable
+ of the first group. y is assumed to be the top variable of the second
+ group. Updates the list of moves. Returns the number of keys in the
+ table if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+zdd_group_move(
+ DdManager * table,
+ int x,
+ int y,
+ Move ** moves)
+{
+ Move *move;
+ int size;
+ int i, temp, gxtop, gxbot, gytop, gybot, yprev;
+ int swapx, swapy;
+
+#ifdef DD_DEBUG
+ assert(x < y); /* we assume that x < y */
+#endif
+ /* Find top and bottom for the two groups. */
+ gxtop = table->subtableZ[x].next;
+ gytop = y;
+ gxbot = x;
+ gybot = table->subtableZ[y].next;
+ while (table->subtableZ[gybot].next != (unsigned) y)
+ gybot = table->subtableZ[gybot].next;
+ yprev = gybot;
+
+ while (x <= y) {
+ while (y > gxtop) {
+ /* Set correct symmetries. */
+ temp = table->subtableZ[x].next;
+ if (temp == x)
+ temp = y;
+ i = gxtop;
+ for (;;) {
+ if (table->subtableZ[i].next == (unsigned) x) {
+ table->subtableZ[i].next = y;
+ break;
+ } else {
+ i = table->subtableZ[i].next;
+ }
+ }
+ if (table->subtableZ[y].next != (unsigned) y) {
+ table->subtableZ[x].next = table->subtableZ[y].next;
+ } else {
+ table->subtableZ[x].next = x;
+ }
+
+ if (yprev != y) {
+ table->subtableZ[yprev].next = x;
+ } else {
+ yprev = x;
+ }
+ table->subtableZ[y].next = temp;
+
+ size = cuddZddSwapInPlace(table, x, y);
+ if (size == 0)
+ goto zdd_group_moveOutOfMem;
+ swapx = x;
+ swapy = y;
+ y = x;
+ x--;
+ } /* while y > gxtop */
+
+ /* Trying to find the next y. */
+ if (table->subtableZ[y].next <= (unsigned) y) {
+ gybot = y;
+ } else {
+ y = table->subtableZ[y].next;
+ }
+
+ yprev = gxtop;
+ gxtop++;
+ gxbot++;
+ x = gxbot;
+ } /* while x <= y, end of group movement */
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto zdd_group_moveOutOfMem;
+ move->x = swapx;
+ move->y = swapy;
+ move->size = table->keysZ;
+ move->next = *moves;
+ *moves = move;
+
+ return(table->keysZ);
+
+zdd_group_moveOutOfMem:
+ while (*moves != NULL) {
+ move = (*moves)->next;
+ cuddDeallocNode(table, (DdNode *)(*moves));
+ *moves = move;
+ }
+ return(0);
+
+} /* end of zdd_group_move */
+
+
+/**Function********************************************************************
+
+ Synopsis [Undoes the swap of two groups.]
+
+ Description [Undoes the swap of two groups. x is assumed to be the
+ bottom variable of the first group. y is assumed to be the top
+ variable of the second group. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+zdd_group_move_backward(
+ DdManager * table,
+ int x,
+ int y)
+{
+ int size;
+ int i, temp, gxtop, gxbot, gytop, gybot, yprev;
+
+#ifdef DD_DEBUG
+ assert(x < y); /* we assume that x < y */
+#endif
+ /* Find top and bottom of the two groups. */
+ gxtop = table->subtableZ[x].next;
+ gytop = y;
+ gxbot = x;
+ gybot = table->subtableZ[y].next;
+ while (table->subtableZ[gybot].next != (unsigned) y)
+ gybot = table->subtableZ[gybot].next;
+ yprev = gybot;
+
+ while (x <= y) {
+ while (y > gxtop) {
+ /* Set correct symmetries. */
+ temp = table->subtableZ[x].next;
+ if (temp == x)
+ temp = y;
+ i = gxtop;
+ for (;;) {
+ if (table->subtableZ[i].next == (unsigned) x) {
+ table->subtableZ[i].next = y;
+ break;
+ } else {
+ i = table->subtableZ[i].next;
+ }
+ }
+ if (table->subtableZ[y].next != (unsigned) y) {
+ table->subtableZ[x].next = table->subtableZ[y].next;
+ } else {
+ table->subtableZ[x].next = x;
+ }
+
+ if (yprev != y) {
+ table->subtableZ[yprev].next = x;
+ } else {
+ yprev = x;
+ }
+ table->subtableZ[y].next = temp;
+
+ size = cuddZddSwapInPlace(table, x, y);
+ if (size == 0)
+ return(0);
+ y = x;
+ x--;
+ } /* while y > gxtop */
+
+ /* Trying to find the next y. */
+ if (table->subtableZ[y].next <= (unsigned) y) {
+ gybot = y;
+ } else {
+ y = table->subtableZ[y].next;
+ }
+
+ yprev = gxtop;
+ gxtop++;
+ gxbot++;
+ x = gxbot;
+ } /* while x <= y, end of group movement backward */
+
+ return(size);
+
+} /* end of zdd_group_move_backward */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts numbers of symmetric variables and symmetry
+ groups.]
+
+ Description []
+
+ SideEffects [None]
+
+******************************************************************************/
+static void
+cuddZddSymmSummary(
+ DdManager * table,
+ int lower,
+ int upper,
+ int * symvars,
+ int * symgroups)
+{
+ int i,x,gbot;
+ int TotalSymm = 0;
+ int TotalSymmGroups = 0;
+
+ for (i = lower; i <= upper; i++) {
+ if (table->subtableZ[i].next != (unsigned) i) {
+ TotalSymmGroups++;
+ x = i;
+ do {
+ TotalSymm++;
+ gbot = x;
+ x = table->subtableZ[x].next;
+ } while (x != i);
+#ifdef DD_DEBUG
+ assert(table->subtableZ[gbot].next == (unsigned) i);
+#endif
+ i = gbot;
+ }
+ }
+ *symvars = TotalSymm;
+ *symgroups = TotalSymmGroups;
+
+ return;
+
+} /* end of cuddZddSymmSummary */
+
diff --git a/src/bdd/cudd/cuddZddUtil.c b/src/bdd/cudd/cuddZddUtil.c
new file mode 100644
index 00000000..0795f123
--- /dev/null
+++ b/src/bdd/cudd/cuddZddUtil.c
@@ -0,0 +1,1021 @@
+/**CFile***********************************************************************
+
+ FileName [cuddZddUtil.c]
+
+ PackageName [cudd]
+
+ Synopsis [Utility functions for ZDDs.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_zddPrintMinterm()
+ <li> Cudd_zddPrintCover()
+ <li> Cudd_zddPrintDebug()
+ <li> Cudd_zddDumpDot()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddZddP()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> zp2()
+ <li> zdd_print_minterm_aux()
+ </ul>
+ ]
+
+ SeeAlso []
+
+ Author [Hyong-Kyoon Shin, In-Ho Moon]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddZddUtil.c,v 1.1.1.1 2003/02/24 22:23:54 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int zp2 ARGS((DdManager *zdd, DdNode *f, st_table *t));
+static void zdd_print_minterm_aux ARGS((DdManager *zdd, DdNode *node, int level, int *list));
+static void zddPrintCoverAux ARGS((DdManager *zdd, DdNode *node, int level, int *list));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints a disjoint sum of product form for a ZDD.]
+
+ Description [Prints a disjoint sum of product form for a ZDD. Returns 1
+ if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddPrintDebug Cudd_zddPrintCover]
+
+******************************************************************************/
+int
+Cudd_zddPrintMinterm(
+ DdManager * zdd,
+ DdNode * node)
+{
+ int i, size;
+ int *list;
+
+ size = (int)zdd->sizeZ;
+ list = ALLOC(int, size);
+ if (list == NULL) {
+ zdd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (i = 0; i < size; i++) list[i] = 3; /* bogus value should disappear */
+ zdd_print_minterm_aux(zdd, node, 0, list);
+ FREE(list);
+ return(1);
+
+} /* end of Cudd_zddPrintMinterm */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints a sum of products from a ZDD representing a cover.]
+
+ Description [Prints a sum of products from a ZDD representing a cover.
+ Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddPrintMinterm]
+
+******************************************************************************/
+int
+Cudd_zddPrintCover(
+ DdManager * zdd,
+ DdNode * node)
+{
+ int i, size;
+ int *list;
+
+ size = (int)zdd->sizeZ;
+ if (size % 2 != 0) return(0); /* number of variables should be even */
+ list = ALLOC(int, size);
+ if (list == NULL) {
+ zdd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ for (i = 0; i < size; i++) list[i] = 3; /* bogus value should disappear */
+ zddPrintCoverAux(zdd, node, 0, list);
+ FREE(list);
+ return(1);
+
+} /* end of Cudd_zddPrintCover */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints to the standard output a ZDD and its statistics.]
+
+ Description [Prints to the standard output a DD and its statistics.
+ The statistics include the number of nodes and the number of minterms.
+ (The number of minterms is also the number of combinations in the set.)
+ The statistics are printed if pr &gt; 0. Specifically:
+ <ul>
+ <li> pr = 0 : prints nothing
+ <li> pr = 1 : prints counts of nodes and minterms
+ <li> pr = 2 : prints counts + disjoint sum of products
+ <li> pr = 3 : prints counts + list of nodes
+ <li> pr &gt; 3 : prints counts + disjoint sum of products + list of nodes
+ </ul>
+ Returns 1 if successful; 0 otherwise.
+ ]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+Cudd_zddPrintDebug(
+ DdManager * zdd,
+ DdNode * f,
+ int n,
+ int pr)
+{
+ DdNode *empty = DD_ZERO(zdd);
+ int nodes;
+ double minterms;
+ int retval = 1;
+
+ if (f == empty && pr > 0) {
+ (void) fprintf(zdd->out,": is the empty ZDD\n");
+ (void) fflush(zdd->out);
+ return(1);
+ }
+
+ if (pr > 0) {
+ nodes = Cudd_zddDagSize(f);
+ if (nodes == CUDD_OUT_OF_MEM) retval = 0;
+ minterms = Cudd_zddCountMinterm(zdd, f, n);
+ if (minterms == (double)CUDD_OUT_OF_MEM) retval = 0;
+ (void) fprintf(zdd->out,": %d nodes %g minterms\n",
+ nodes, minterms);
+ if (pr > 2)
+ if (!cuddZddP(zdd, f)) retval = 0;
+ if (pr == 2 || pr > 3) {
+ if (!Cudd_zddPrintMinterm(zdd, f)) retval = 0;
+ (void) fprintf(zdd->out,"\n");
+ }
+ (void) fflush(zdd->out);
+ }
+ return(retval);
+
+} /* end of Cudd_zddPrintDebug */
+
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds the first path of a ZDD.]
+
+ Description [Defines an iterator on the paths of a ZDD
+ and finds its first path. Returns a generator that contains the
+ information necessary to continue the enumeration if successful; NULL
+ otherwise.<p>
+ A path is represented as an array of literals, which are integers in
+ {0, 1, 2}; 0 represents an else arc out of a node, 1 represents a then arc
+ out of a node, and 2 stands for the absence of a node.
+ The size of the array equals the number of variables in the manager at
+ the time Cudd_zddFirstCube is called.<p>
+ The paths that end in the empty terminal are not enumerated.]
+
+ SideEffects [The first path is returned as a side effect.]
+
+ SeeAlso [Cudd_zddForeachPath Cudd_zddNextPath Cudd_GenFree
+ Cudd_IsGenEmpty]
+
+******************************************************************************/
+DdGen *
+Cudd_zddFirstPath(
+ DdManager * zdd,
+ DdNode * f,
+ int ** path)
+{
+ DdGen *gen;
+ DdNode *top, *next, *prev;
+ int i;
+ int nvars;
+
+ /* Sanity Check. */
+ if (zdd == NULL || f == NULL) return(NULL);
+
+ /* Allocate generator an initialize it. */
+ gen = ALLOC(DdGen,1);
+ if (gen == NULL) {
+ zdd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+
+ gen->manager = zdd;
+ gen->type = CUDD_GEN_ZDD_PATHS;
+ gen->status = CUDD_GEN_EMPTY;
+ gen->gen.cubes.cube = NULL;
+ gen->gen.cubes.value = DD_ZERO_VAL;
+ gen->stack.sp = 0;
+ gen->stack.stack = NULL;
+ gen->node = NULL;
+
+ nvars = zdd->sizeZ;
+ gen->gen.cubes.cube = ALLOC(int,nvars);
+ if (gen->gen.cubes.cube == NULL) {
+ zdd->errorCode = CUDD_MEMORY_OUT;
+ FREE(gen);
+ return(NULL);
+ }
+ for (i = 0; i < nvars; i++) gen->gen.cubes.cube[i] = 2;
+
+ /* The maximum stack depth is one plus the number of variables.
+ ** because a path may have nodes at all levels, including the
+ ** constant level.
+ */
+ gen->stack.stack = ALLOC(DdNode *, nvars+1);
+ if (gen->stack.stack == NULL) {
+ zdd->errorCode = CUDD_MEMORY_OUT;
+ FREE(gen->gen.cubes.cube);
+ FREE(gen);
+ return(NULL);
+ }
+ for (i = 0; i <= nvars; i++) gen->stack.stack[i] = NULL;
+
+ /* Find the first path of the ZDD. */
+ gen->stack.stack[gen->stack.sp] = f; gen->stack.sp++;
+
+ while (1) {
+ top = gen->stack.stack[gen->stack.sp-1];
+ if (!cuddIsConstant(top)) {
+ /* Take the else branch first. */
+ gen->gen.cubes.cube[top->index] = 0;
+ next = cuddE(top);
+ gen->stack.stack[gen->stack.sp] = next; gen->stack.sp++;
+ } else if (top == DD_ZERO(zdd)) {
+ /* Backtrack. */
+ while (1) {
+ if (gen->stack.sp == 1) {
+ /* The current node has no predecessor. */
+ gen->status = CUDD_GEN_EMPTY;
+ gen->stack.sp--;
+ goto done;
+ }
+ prev = gen->stack.stack[gen->stack.sp-2];
+ next = cuddT(prev);
+ if (next != top) { /* follow the then branch next */
+ gen->gen.cubes.cube[prev->index] = 1;
+ gen->stack.stack[gen->stack.sp-1] = next;
+ break;
+ }
+ /* Pop the stack and try again. */
+ gen->gen.cubes.cube[prev->index] = 2;
+ gen->stack.sp--;
+ top = gen->stack.stack[gen->stack.sp-1];
+ }
+ } else {
+ gen->status = CUDD_GEN_NONEMPTY;
+ gen->gen.cubes.value = cuddV(top);
+ goto done;
+ }
+ }
+
+done:
+ *path = gen->gen.cubes.cube;
+ return(gen);
+
+} /* end of Cudd_zddFirstPath */
+
+
+/**Function********************************************************************
+
+ Synopsis [Generates the next path of a ZDD.]
+
+ Description [Generates the next path of a ZDD onset,
+ using generator gen. Returns 0 if the enumeration is completed; 1
+ otherwise.]
+
+ SideEffects [The path is returned as a side effect. The
+ generator is modified.]
+
+ SeeAlso [Cudd_zddForeachPath Cudd_zddFirstPath Cudd_GenFree
+ Cudd_IsGenEmpty]
+
+******************************************************************************/
+int
+Cudd_zddNextPath(
+ DdGen * gen,
+ int ** path)
+{
+ DdNode *top, *next, *prev;
+ DdManager *zdd = gen->manager;
+
+ /* Backtrack from previously reached terminal node. */
+ while (1) {
+ if (gen->stack.sp == 1) {
+ /* The current node has no predecessor. */
+ gen->status = CUDD_GEN_EMPTY;
+ gen->stack.sp--;
+ goto done;
+ }
+ top = gen->stack.stack[gen->stack.sp-1];
+ prev = gen->stack.stack[gen->stack.sp-2];
+ next = cuddT(prev);
+ if (next != top) { /* follow the then branch next */
+ gen->gen.cubes.cube[prev->index] = 1;
+ gen->stack.stack[gen->stack.sp-1] = next;
+ break;
+ }
+ /* Pop the stack and try again. */
+ gen->gen.cubes.cube[prev->index] = 2;
+ gen->stack.sp--;
+ }
+
+ while (1) {
+ top = gen->stack.stack[gen->stack.sp-1];
+ if (!cuddIsConstant(top)) {
+ /* Take the else branch first. */
+ gen->gen.cubes.cube[top->index] = 0;
+ next = cuddE(top);
+ gen->stack.stack[gen->stack.sp] = next; gen->stack.sp++;
+ } else if (top == DD_ZERO(zdd)) {
+ /* Backtrack. */
+ while (1) {
+ if (gen->stack.sp == 1) {
+ /* The current node has no predecessor. */
+ gen->status = CUDD_GEN_EMPTY;
+ gen->stack.sp--;
+ goto done;
+ }
+ prev = gen->stack.stack[gen->stack.sp-2];
+ next = cuddT(prev);
+ if (next != top) { /* follow the then branch next */
+ gen->gen.cubes.cube[prev->index] = 1;
+ gen->stack.stack[gen->stack.sp-1] = next;
+ break;
+ }
+ /* Pop the stack and try again. */
+ gen->gen.cubes.cube[prev->index] = 2;
+ gen->stack.sp--;
+ top = gen->stack.stack[gen->stack.sp-1];
+ }
+ } else {
+ gen->status = CUDD_GEN_NONEMPTY;
+ gen->gen.cubes.value = cuddV(top);
+ goto done;
+ }
+ }
+
+done:
+ if (gen->status == CUDD_GEN_EMPTY) return(0);
+ *path = gen->gen.cubes.cube;
+ return(1);
+
+} /* end of Cudd_zddNextPath */
+
+
+/**Function********************************************************************
+
+ Synopsis [Converts a path of a ZDD representing a cover to a string.]
+
+ Description [Converts a path of a ZDD representing a cover to a
+ string. The string represents an implicant of the cover. The path
+ is typically produced by Cudd_zddForeachPath. Returns a pointer to
+ the string if successful; NULL otherwise. If the str input is NULL,
+ it allocates a new string. The string passed to this function must
+ have enough room for all variables and for the terminator.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddForeachPath]
+
+******************************************************************************/
+char *
+Cudd_zddCoverPathToString(
+ DdManager *zdd /* DD manager */,
+ int *path /* path of ZDD representing a cover */,
+ char *str /* pointer to string to use if != NULL */
+ )
+{
+ int nvars = zdd->sizeZ;
+ int i;
+ char *res;
+
+ if (nvars & 1) return(NULL);
+ nvars >>= 1;
+ if (str == NULL) {
+ res = ALLOC(char, nvars+1);
+ if (res == NULL) return(NULL);
+ } else {
+ res = str;
+ }
+ for (i = 0; i < nvars; i++) {
+ int v = (path[2*i] << 2) | path[2*i+1];
+ switch (v) {
+ case 0:
+ case 2:
+ case 8:
+ case 10:
+ res[i] = '-';
+ break;
+ case 1:
+ case 9:
+ res[i] = '0';
+ break;
+ case 4:
+ case 6:
+ res[i] = '1';
+ break;
+ default:
+ res[i] = '?';
+ }
+ }
+ res[nvars] = 0;
+
+ return(res);
+
+} /* end of Cudd_zddCoverPathToString */
+
+
+/**Function********************************************************************
+
+ Synopsis [Writes a dot file representing the argument ZDDs.]
+
+ Description [Writes a file representing the argument ZDDs in a format
+ suitable for the graph drawing program dot.
+ It returns 1 in case of success; 0 otherwise (e.g., out-of-memory,
+ file system full).
+ Cudd_zddDumpDot does not close the file: This is the caller
+ responsibility. Cudd_zddDumpDot uses a minimal unique subset of the
+ hexadecimal address of a node as name for it.
+ If the argument inames is non-null, it is assumed to hold the pointers
+ to the names of the inputs. Similarly for onames.
+ Cudd_zddDumpDot uses the following convention to draw arcs:
+ <ul>
+ <li> solid line: THEN arcs;
+ <li> dashed line: ELSE arcs.
+ </ul>
+ The dot options are chosen so that the drawing fits on a letter-size
+ sheet.
+ ]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_DumpDot Cudd_zddPrintDebug]
+
+******************************************************************************/
+int
+Cudd_zddDumpDot(
+ DdManager * dd /* manager */,
+ int n /* number of output nodes to be dumped */,
+ DdNode ** f /* array of output nodes to be dumped */,
+ char ** inames /* array of input names (or NULL) */,
+ char ** onames /* array of output names (or NULL) */,
+ FILE * fp /* pointer to the dump file */)
+{
+ DdNode *support = NULL;
+ DdNode *scan;
+ int *sorted = NULL;
+ int nvars = dd->sizeZ;
+ st_table *visited = NULL;
+ st_generator *gen;
+ int retval;
+ int i, j;
+ int slots;
+ DdNodePtr *nodelist;
+ long refAddr, diff, mask;
+
+ /* Build a bit array with the support of f. */
+ sorted = ALLOC(int,nvars);
+ if (sorted == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ goto failure;
+ }
+ for (i = 0; i < nvars; i++) sorted[i] = 0;
+
+ /* Take the union of the supports of each output function. */
+ for (i = 0; i < n; i++) {
+ support = Cudd_Support(dd,f[i]);
+ if (support == NULL) goto failure;
+ cuddRef(support);
+ scan = support;
+ while (!cuddIsConstant(scan)) {
+ sorted[scan->index] = 1;
+ scan = cuddT(scan);
+ }
+ Cudd_RecursiveDeref(dd,support);
+ }
+ support = NULL; /* so that we do not try to free it in case of failure */
+
+ /* Initialize symbol table for visited nodes. */
+ visited = st_init_table(st_ptrcmp, st_ptrhash);
+ if (visited == NULL) goto failure;
+
+ /* Collect all the nodes of this DD in the symbol table. */
+ for (i = 0; i < n; i++) {
+ retval = cuddCollectNodes(f[i],visited);
+ if (retval == 0) goto failure;
+ }
+
+ /* Find how many most significant hex digits are identical
+ ** in the addresses of all the nodes. Build a mask based
+ ** on this knowledge, so that digits that carry no information
+ ** will not be printed. This is done in two steps.
+ ** 1. We scan the symbol table to find the bits that differ
+ ** in at least 2 addresses.
+ ** 2. We choose one of the possible masks. There are 8 possible
+ ** masks for 32-bit integer, and 16 possible masks for 64-bit
+ ** integers.
+ */
+
+ /* Find the bits that are different. */
+ refAddr = (long) f[0];
+ diff = 0;
+ gen = st_init_gen(visited);
+ while (st_gen(gen, (char **) &scan, NULL)) {
+ diff |= refAddr ^ (long) scan;
+ }
+ st_free_gen(gen);
+
+ /* Choose the mask. */
+ for (i = 0; (unsigned) i < 8 * sizeof(long); i += 4) {
+ mask = (1 << i) - 1;
+ if (diff <= mask) break;
+ }
+
+ /* Write the header and the global attributes. */
+ retval = fprintf(fp,"digraph \"ZDD\" {\n");
+ if (retval == EOF) return(0);
+ retval = fprintf(fp,
+ "size = \"7.5,10\"\ncenter = true;\nedge [dir = none];\n");
+ if (retval == EOF) return(0);
+
+ /* Write the input name subgraph by scanning the support array. */
+ retval = fprintf(fp,"{ node [shape = plaintext];\n");
+ if (retval == EOF) goto failure;
+ retval = fprintf(fp," edge [style = invis];\n");
+ if (retval == EOF) goto failure;
+ /* We use a name ("CONST NODES") with an embedded blank, because
+ ** it is unlikely to appear as an input name.
+ */
+ retval = fprintf(fp," \"CONST NODES\" [style = invis];\n");
+ if (retval == EOF) goto failure;
+ for (i = 0; i < nvars; i++) {
+ if (sorted[dd->invpermZ[i]]) {
+ if (inames == NULL) {
+ retval = fprintf(fp,"\" %d \" -> ", dd->invpermZ[i]);
+ } else {
+ retval = fprintf(fp,"\" %s \" -> ", inames[dd->invpermZ[i]]);
+ }
+ if (retval == EOF) goto failure;
+ }
+ }
+ retval = fprintf(fp,"\"CONST NODES\"; \n}\n");
+ if (retval == EOF) goto failure;
+
+ /* Write the output node subgraph. */
+ retval = fprintf(fp,"{ rank = same; node [shape = box]; edge [style = invis];\n");
+ if (retval == EOF) goto failure;
+ for (i = 0; i < n; i++) {
+ if (onames == NULL) {
+ retval = fprintf(fp,"\"F%d\"", i);
+ } else {
+ retval = fprintf(fp,"\" %s \"", onames[i]);
+ }
+ if (retval == EOF) goto failure;
+ if (i == n - 1) {
+ retval = fprintf(fp,"; }\n");
+ } else {
+ retval = fprintf(fp," -> ");
+ }
+ if (retval == EOF) goto failure;
+ }
+
+ /* Write rank info: All nodes with the same index have the same rank. */
+ for (i = 0; i < nvars; i++) {
+ if (sorted[dd->invpermZ[i]]) {
+ retval = fprintf(fp,"{ rank = same; ");
+ if (retval == EOF) goto failure;
+ if (inames == NULL) {
+ retval = fprintf(fp,"\" %d \";\n", dd->invpermZ[i]);
+ } else {
+ retval = fprintf(fp,"\" %s \";\n", inames[dd->invpermZ[i]]);
+ }
+ if (retval == EOF) goto failure;
+ nodelist = dd->subtableZ[i].nodelist;
+ slots = dd->subtableZ[i].slots;
+ for (j = 0; j < slots; j++) {
+ scan = nodelist[j];
+ while (scan != NULL) {
+ if (st_is_member(visited,(char *) scan)) {
+ retval = fprintf(fp,"\"%lx\";\n", (mask & (long) scan) / sizeof(DdNode));
+ if (retval == EOF) goto failure;
+ }
+ scan = scan->next;
+ }
+ }
+ retval = fprintf(fp,"}\n");
+ if (retval == EOF) goto failure;
+ }
+ }
+
+ /* All constants have the same rank. */
+ retval = fprintf(fp,
+ "{ rank = same; \"CONST NODES\";\n{ node [shape = box]; ");
+ if (retval == EOF) goto failure;
+ nodelist = dd->constants.nodelist;
+ slots = dd->constants.slots;
+ for (j = 0; j < slots; j++) {
+ scan = nodelist[j];
+ while (scan != NULL) {
+ if (st_is_member(visited,(char *) scan)) {
+ retval = fprintf(fp,"\"%lx\";\n", (mask & (long) scan) / sizeof(DdNode));
+ if (retval == EOF) goto failure;
+ }
+ scan = scan->next;
+ }
+ }
+ retval = fprintf(fp,"}\n}\n");
+ if (retval == EOF) goto failure;
+
+ /* Write edge info. */
+ /* Edges from the output nodes. */
+ for (i = 0; i < n; i++) {
+ if (onames == NULL) {
+ retval = fprintf(fp,"\"F%d\"", i);
+ } else {
+ retval = fprintf(fp,"\" %s \"", onames[i]);
+ }
+ if (retval == EOF) goto failure;
+ retval = fprintf(fp," -> \"%lx\" [style = solid];\n",
+ (mask & (long) f[i]) / sizeof(DdNode));
+ if (retval == EOF) goto failure;
+ }
+
+ /* Edges from internal nodes. */
+ for (i = 0; i < nvars; i++) {
+ if (sorted[dd->invpermZ[i]]) {
+ nodelist = dd->subtableZ[i].nodelist;
+ slots = dd->subtableZ[i].slots;
+ for (j = 0; j < slots; j++) {
+ scan = nodelist[j];
+ while (scan != NULL) {
+ if (st_is_member(visited,(char *) scan)) {
+ retval = fprintf(fp,
+ "\"%lx\" -> \"%lx\";\n",
+ (mask & (long) scan) / sizeof(DdNode),
+ (mask & (long) cuddT(scan)) / sizeof(DdNode));
+ if (retval == EOF) goto failure;
+ retval = fprintf(fp,
+ "\"%lx\" -> \"%lx\" [style = dashed];\n",
+ (mask & (long) scan) / sizeof(DdNode),
+ (mask & (long) cuddE(scan)) / sizeof(DdNode));
+ if (retval == EOF) goto failure;
+ }
+ scan = scan->next;
+ }
+ }
+ }
+ }
+
+ /* Write constant labels. */
+ nodelist = dd->constants.nodelist;
+ slots = dd->constants.slots;
+ for (j = 0; j < slots; j++) {
+ scan = nodelist[j];
+ while (scan != NULL) {
+ if (st_is_member(visited,(char *) scan)) {
+ retval = fprintf(fp,"\"%lx\" [label = \"%g\"];\n",
+ (mask & (long) scan) / sizeof(DdNode), cuddV(scan));
+ if (retval == EOF) goto failure;
+ }
+ scan = scan->next;
+ }
+ }
+
+ /* Write trailer and return. */
+ retval = fprintf(fp,"}\n");
+ if (retval == EOF) goto failure;
+
+ st_free_table(visited);
+ FREE(sorted);
+ return(1);
+
+failure:
+ if (sorted != NULL) FREE(sorted);
+ if (support != NULL) Cudd_RecursiveDeref(dd,support);
+ if (visited != NULL) st_free_table(visited);
+ return(0);
+
+} /* end of Cudd_zddDumpBlif */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints a ZDD to the standard output. One line per node is
+ printed.]
+
+ Description [Prints a ZDD to the standard output. One line per node is
+ printed. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_zddPrintDebug]
+
+******************************************************************************/
+int
+cuddZddP(
+ DdManager * zdd,
+ DdNode * f)
+{
+ int retval;
+ st_table *table = st_init_table(st_ptrcmp, st_ptrhash);
+
+ if (table == NULL) return(0);
+
+ retval = zp2(zdd, f, table);
+ st_free_table(table);
+ (void) fputc('\n', zdd->out);
+ return(retval);
+
+} /* end of cuddZddP */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of cuddZddP.]
+
+ Description [Performs the recursive step of cuddZddP. Returns 1 in
+ case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+zp2(
+ DdManager * zdd,
+ DdNode * f,
+ st_table * t)
+{
+ DdNode *n;
+ int T, E;
+ DdNode *base = DD_ONE(zdd);
+
+ if (f == NULL)
+ return(0);
+
+ if (Cudd_IsConstant(f)) {
+ (void)fprintf(zdd->out, "ID = %d\n", (f == base));
+ return(1);
+ }
+ if (st_is_member(t, (char *)f) == 1)
+ return(1);
+
+ if (st_insert(t, (char *) f, NULL) == ST_OUT_OF_MEM)
+ return(0);
+
+#if SIZEOF_VOID_P == 8
+ (void) fprintf(zdd->out, "ID = 0x%lx\tindex = %d\tr = %d\t",
+ (unsigned long)f / (unsigned long) sizeof(DdNode), f->index, f->ref);
+#else
+ (void) fprintf(zdd->out, "ID = 0x%x\tindex = %d\tr = %d\t",
+ (unsigned)f / (unsigned) sizeof(DdNode), f->index, f->ref);
+#endif
+
+ n = cuddT(f);
+ if (Cudd_IsConstant(n)) {
+ (void) fprintf(zdd->out, "T = %d\t\t", (n == base));
+ T = 1;
+ } else {
+#if SIZEOF_VOID_P == 8
+ (void) fprintf(zdd->out, "T = 0x%lx\t", (unsigned long) n /
+ (unsigned long) sizeof(DdNode));
+#else
+ (void) fprintf(zdd->out, "T = 0x%x\t", (unsigned) n / (unsigned) sizeof(DdNode));
+#endif
+ T = 0;
+ }
+
+ n = cuddE(f);
+ if (Cudd_IsConstant(n)) {
+ (void) fprintf(zdd->out, "E = %d\n", (n == base));
+ E = 1;
+ } else {
+#if SIZEOF_VOID_P == 8
+ (void) fprintf(zdd->out, "E = 0x%lx\n", (unsigned long) n /
+ (unsigned long) sizeof(DdNode));
+#else
+ (void) fprintf(zdd->out, "E = 0x%x\n", (unsigned) n / (unsigned) sizeof(DdNode));
+#endif
+ E = 0;
+ }
+
+ if (E == 0)
+ if (zp2(zdd, cuddE(f), t) == 0) return(0);
+ if (T == 0)
+ if (zp2(zdd, cuddT(f), t) == 0) return(0);
+ return(1);
+
+} /* end of zp2 */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddPrintMinterm.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+zdd_print_minterm_aux(
+ DdManager * zdd /* manager */,
+ DdNode * node /* current node */,
+ int level /* depth in the recursion */,
+ int * list /* current recursion path */)
+{
+ DdNode *Nv, *Nnv;
+ int i, v;
+ DdNode *base = DD_ONE(zdd);
+
+ if (Cudd_IsConstant(node)) {
+ if (node == base) {
+ /* Check for missing variable. */
+ if (level != zdd->sizeZ) {
+ list[zdd->invpermZ[level]] = 0;
+ zdd_print_minterm_aux(zdd, node, level + 1, list);
+ return;
+ }
+ /* Terminal case: Print one cube based on the current recursion
+ ** path.
+ */
+ for (i = 0; i < zdd->sizeZ; i++) {
+ v = list[i];
+ if (v == 0)
+ (void) fprintf(zdd->out,"0");
+ else if (v == 1)
+ (void) fprintf(zdd->out,"1");
+ else if (v == 3)
+ (void) fprintf(zdd->out,"@"); /* should never happen */
+ else
+ (void) fprintf(zdd->out,"-");
+ }
+ (void) fprintf(zdd->out," 1\n");
+ }
+ } else {
+ /* Check for missing variable. */
+ if (level != cuddIZ(zdd,node->index)) {
+ list[zdd->invpermZ[level]] = 0;
+ zdd_print_minterm_aux(zdd, node, level + 1, list);
+ return;
+ }
+
+ Nnv = cuddE(node);
+ Nv = cuddT(node);
+ if (Nv == Nnv) {
+ list[node->index] = 2;
+ zdd_print_minterm_aux(zdd, Nnv, level + 1, list);
+ return;
+ }
+
+ list[node->index] = 1;
+ zdd_print_minterm_aux(zdd, Nv, level + 1, list);
+ list[node->index] = 0;
+ zdd_print_minterm_aux(zdd, Nnv, level + 1, list);
+ }
+ return;
+
+} /* end of zdd_print_minterm_aux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_zddPrintCover.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+zddPrintCoverAux(
+ DdManager * zdd /* manager */,
+ DdNode * node /* current node */,
+ int level /* depth in the recursion */,
+ int * list /* current recursion path */)
+{
+ DdNode *Nv, *Nnv;
+ int i, v;
+ DdNode *base = DD_ONE(zdd);
+
+ if (Cudd_IsConstant(node)) {
+ if (node == base) {
+ /* Check for missing variable. */
+ if (level != zdd->sizeZ) {
+ list[zdd->invpermZ[level]] = 0;
+ zddPrintCoverAux(zdd, node, level + 1, list);
+ return;
+ }
+ /* Terminal case: Print one cube based on the current recursion
+ ** path.
+ */
+ for (i = 0; i < zdd->sizeZ; i += 2) {
+ v = list[i] * 4 + list[i+1];
+ if (v == 0)
+ (void) putc('-',zdd->out);
+ else if (v == 4)
+ (void) putc('1',zdd->out);
+ else if (v == 1)
+ (void) putc('0',zdd->out);
+ else
+ (void) putc('@',zdd->out); /* should never happen */
+ }
+ (void) fprintf(zdd->out," 1\n");
+ }
+ } else {
+ /* Check for missing variable. */
+ if (level != cuddIZ(zdd,node->index)) {
+ list[zdd->invpermZ[level]] = 0;
+ zddPrintCoverAux(zdd, node, level + 1, list);
+ return;
+ }
+
+ Nnv = cuddE(node);
+ Nv = cuddT(node);
+ if (Nv == Nnv) {
+ list[node->index] = 2;
+ zddPrintCoverAux(zdd, Nnv, level + 1, list);
+ return;
+ }
+
+ list[node->index] = 1;
+ zddPrintCoverAux(zdd, Nv, level + 1, list);
+ list[node->index] = 0;
+ zddPrintCoverAux(zdd, Nnv, level + 1, list);
+ }
+ return;
+
+} /* end of zddPrintCoverAux */
diff --git a/src/bdd/cudd/module.make b/src/bdd/cudd/module.make
new file mode 100644
index 00000000..c526a50e
--- /dev/null
+++ b/src/bdd/cudd/module.make
@@ -0,0 +1,61 @@
+SRC += src/bdd/cudd/cuddAPI.c \
+ src/bdd/cudd/cuddAddAbs.c \
+ src/bdd/cudd/cuddAddApply.c \
+ src/bdd/cudd/cuddAddFind.c \
+ src/bdd/cudd/cuddAddInv.c \
+ src/bdd/cudd/cuddAddIte.c \
+ src/bdd/cudd/cuddAddNeg.c \
+ src/bdd/cudd/cuddAddWalsh.c \
+ src/bdd/cudd/cuddAndAbs.c \
+ src/bdd/cudd/cuddAnneal.c \
+ src/bdd/cudd/cuddApa.c \
+ src/bdd/cudd/cuddApprox.c \
+ src/bdd/cudd/cuddBddAbs.c \
+ src/bdd/cudd/cuddBddCorr.c \
+ src/bdd/cudd/cuddBddIte.c \
+ src/bdd/cudd/cuddBridge.c \
+ src/bdd/cudd/cuddCache.c \
+ src/bdd/cudd/cuddCheck.c \
+ src/bdd/cudd/cuddClip.c \
+ src/bdd/cudd/cuddCof.c \
+ src/bdd/cudd/cuddCompose.c \
+ src/bdd/cudd/cuddDecomp.c \
+ src/bdd/cudd/cuddEssent.c \
+ src/bdd/cudd/cuddExact.c \
+ src/bdd/cudd/cuddExport.c \
+ src/bdd/cudd/cuddGenCof.c \
+ src/bdd/cudd/cuddGenetic.c \
+ src/bdd/cudd/cuddGroup.c \
+ src/bdd/cudd/cuddHarwell.c \
+ src/bdd/cudd/cuddInit.c \
+ src/bdd/cudd/cuddInteract.c \
+ src/bdd/cudd/cuddLCache.c \
+ src/bdd/cudd/cuddLevelQ.c \
+ src/bdd/cudd/cuddLinear.c \
+ src/bdd/cudd/cuddLiteral.c \
+ src/bdd/cudd/cuddMatMult.c \
+ src/bdd/cudd/cuddPriority.c \
+ src/bdd/cudd/cuddRead.c \
+ src/bdd/cudd/cuddRef.c \
+ src/bdd/cudd/cuddReorder.c \
+ src/bdd/cudd/cuddSat.c \
+ src/bdd/cudd/cuddSign.c \
+ src/bdd/cudd/cuddSolve.c \
+ src/bdd/cudd/cuddSplit.c \
+ src/bdd/cudd/cuddSubsetHB.c \
+ src/bdd/cudd/cuddSubsetSP.c \
+ src/bdd/cudd/cuddSymmetry.c \
+ src/bdd/cudd/cuddTable.c \
+ src/bdd/cudd/cuddUtil.c \
+ src/bdd/cudd/cuddWindow.c \
+ src/bdd/cudd/cuddZddCount.c \
+ src/bdd/cudd/cuddZddFuncs.c \
+ src/bdd/cudd/cuddZddGroup.c \
+ src/bdd/cudd/cuddZddIsop.c \
+ src/bdd/cudd/cuddZddLin.c \
+ src/bdd/cudd/cuddZddMisc.c \
+ src/bdd/cudd/cuddZddPort.c \
+ src/bdd/cudd/cuddZddReord.c \
+ src/bdd/cudd/cuddZddSetop.c \
+ src/bdd/cudd/cuddZddSymm.c \
+ src/bdd/cudd/cuddZddUtil.c
diff --git a/src/bdd/cudd/r7x8.1.mat b/src/bdd/cudd/r7x8.1.mat
new file mode 100644
index 00000000..b0dd0a0a
--- /dev/null
+++ b/src/bdd/cudd/r7x8.1.mat
@@ -0,0 +1,53 @@
+7 9
+0 0 1
+0 1 1
+0 2 1
+0 3 4
+0 4 3
+0 5 3
+0 6 3
+0 8 3
+1 0 4
+1 1 3
+1 2 2
+1 3 4
+1 4 1
+1 5 2
+1 6 4
+1 8 3
+2 0 1
+2 1 1
+2 2 4
+2 4 2
+2 5 3
+2 6 3
+2 8 3
+3 0 2
+3 1 1
+3 3 4
+3 4 4
+3 5 1
+3 8 1
+4 0 2
+4 1 3
+4 2 2
+4 3 4
+4 4 1
+4 5 1
+4 6 2
+4 8 2
+5 0 3
+5 1 3
+5 2 4
+5 3 4
+5 4 1
+5 5 3
+5 6 3
+5 8 4
+6 1 1
+6 2 1
+6 3 4
+6 4 2
+6 5 4
+6 6 4
+6 8 2
diff --git a/src/bdd/cudd/testcudd.c b/src/bdd/cudd/testcudd.c
new file mode 100644
index 00000000..451bb190
--- /dev/null
+++ b/src/bdd/cudd/testcudd.c
@@ -0,0 +1,988 @@
+/**CFile***********************************************************************
+
+ FileName [testcudd.c]
+
+ PackageName [cudd]
+
+ Synopsis [Sanity check tests for some CUDD functions.]
+
+ Description [testcudd reads a matrix with real coefficients and
+ transforms it into an ADD. It then performs various operations on
+ the ADD and on the BDD corresponding to the ADD pattern. Finally,
+ testcudd tests functions relate to Walsh matrices and matrix
+ multiplication.]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define TESTCUDD_VERSION "TestCudd Version #1.0, Release date 3/17/01"
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: testcudd.c,v 1.1.1.1 2003/02/24 22:23:54 wjiang Exp $";
+#endif
+
+static char *onames[] = { "C", "M" }; /* names of functions to be dumped */
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static void usage ARGS((char * prog));
+static FILE *open_file ARGS((char *filename, char *mode));
+static int testIterators ARGS((DdManager *dd, DdNode *M, DdNode *C, int pr));
+static int testXor ARGS((DdManager *dd, DdNode *f, int pr, int nvars));
+static int testHamming ARGS((DdManager *dd, DdNode *f, int pr, int nvars));
+static int testWalsh ARGS((DdManager *dd, int N, int cmu, int approach, int pr));
+
+/**AutomaticEnd***************************************************************/
+
+
+/**Function********************************************************************
+
+ Synopsis [Main function for testcudd.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+main(int argc, char **argv)
+{
+ FILE *fp; /* pointer to input file */
+ char *file = ""; /* input file name */
+ FILE *dfp = NULL; /* pointer to dump file */
+ char *dfile; /* file for DD dump */
+ DdNode *dfunc[2]; /* addresses of the functions to be dumped */
+ DdManager *dd; /* pointer to DD manager */
+ DdNode *one, *zero; /* fast access to constant functions */
+ DdNode *M;
+ DdNode **x; /* pointers to variables */
+ DdNode **y; /* pointers to variables */
+ DdNode **xn; /* complements of row variables */
+ DdNode **yn_; /* complements of column variables */
+ DdNode **xvars;
+ DdNode **yvars;
+ DdNode *C; /* result of converting from ADD to BDD */
+ DdNode *ess; /* cube of essential variables */
+ DdNode *shortP; /* BDD cube of shortest path */
+ DdNode *largest; /* BDD of largest cube */
+ DdNode *shortA; /* ADD cube of shortest path */
+ DdNode *constN; /* value returned by evaluation of ADD */
+ DdNode *ycube; /* cube of the negated y vars for c-proj */
+ DdNode *CP; /* C-Projection of C */
+ DdNode *CPr; /* C-Selection of C */
+ int length; /* length of the shortest path */
+ int nx; /* number of variables */
+ int ny;
+ int maxnx;
+ int maxny;
+ int m;
+ int n;
+ int N;
+ int cmu; /* use CMU multiplication */
+ int pr; /* verbose printout level */
+ int harwell;
+ int multiple; /* read multiple matrices */
+ int ok;
+ int c; /* variable to read in options */
+ int approach; /* reordering approach */
+ int autodyn; /* automatic reordering */
+ int groupcheck; /* option for group sifting */
+ int profile; /* print heap profile if != 0 */
+ int keepperm; /* keep track of permutation */
+ int clearcache; /* clear the cache after each matrix */
+ int blifOrDot; /* dump format: 0 -> dot, 1 -> blif, ... */
+ int retval; /* return value */
+ int i; /* loop index */
+ long startTime; /* initial time */
+ long lapTime;
+ int size;
+ unsigned int cacheSize, maxMemory;
+ unsigned int nvars,nslots;
+
+ startTime = util_cpu_time();
+
+ approach = CUDD_REORDER_NONE;
+ autodyn = 0;
+ pr = 0;
+ harwell = 0;
+ multiple = 0;
+ profile = 0;
+ keepperm = 0;
+ cmu = 0;
+ N = 4;
+ nvars = 4;
+ cacheSize = 127;
+ maxMemory = 0;
+ nslots = CUDD_UNIQUE_SLOTS;
+ clearcache = 0;
+ groupcheck = CUDD_GROUP_CHECK7;
+ dfile = NULL;
+ blifOrDot = 0; /* dot format */
+
+ /* Parse command line. */
+ while ((c = util_getopt(argc, argv, "CDHMPS:a:bcd:g:hkmn:p:v:x:X:"))
+ != EOF) {
+ switch(c) {
+ case 'C':
+ cmu = 1;
+ break;
+ case 'D':
+ autodyn = 1;
+ break;
+ case 'H':
+ harwell = 1;
+ break;
+ case 'M':
+#ifdef MNEMOSYNE
+ (void) mnem_setrecording(0);
+#endif
+ break;
+ case 'P':
+ profile = 1;
+ break;
+ case 'S':
+ nslots = atoi(util_optarg);
+ break;
+ case 'X':
+ maxMemory = atoi(util_optarg);
+ break;
+ case 'a':
+ approach = atoi(util_optarg);
+ break;
+ case 'b':
+ blifOrDot = 1; /* blif format */
+ break;
+ case 'c':
+ clearcache = 1;
+ break;
+ case 'd':
+ dfile = util_optarg;
+ break;
+ case 'g':
+ groupcheck = atoi(util_optarg);
+ break;
+ case 'k':
+ keepperm = 1;
+ break;
+ case 'm':
+ multiple = 1;
+ break;
+ case 'n':
+ N = atoi(util_optarg);
+ break;
+ case 'p':
+ pr = atoi(util_optarg);
+ break;
+ case 'v':
+ nvars = atoi(util_optarg);
+ break;
+ case 'x':
+ cacheSize = atoi(util_optarg);
+ break;
+ case 'h':
+ default:
+ usage(argv[0]);
+ break;
+ }
+ }
+
+ if (argc - util_optind == 0) {
+ file = "-";
+ } else if (argc - util_optind == 1) {
+ file = argv[util_optind];
+ } else {
+ usage(argv[0]);
+ }
+ if ((approach<0) || (approach>17)) {
+ (void) fprintf(stderr,"Invalid approach: %d \n",approach);
+ usage(argv[0]);
+ }
+
+ if (pr >= 0) {
+ (void) printf("# %s\n", TESTCUDD_VERSION);
+ /* Echo command line and arguments. */
+ (void) printf("#");
+ for (i = 0; i < argc; i++) {
+ (void) printf(" %s", argv[i]);
+ }
+ (void) printf("\n");
+ (void) fflush(stdout);
+ }
+
+ /* Initialize manager and provide easy reference to terminals. */
+ dd = Cudd_Init(nvars,0,nslots,cacheSize,maxMemory);
+ one = DD_ONE(dd);
+ zero = DD_ZERO(dd);
+ dd->groupcheck = (Cudd_AggregationType) groupcheck;
+ if (autodyn) Cudd_AutodynEnable(dd,CUDD_REORDER_SAME);
+
+ /* Open input file. */
+ fp = open_file(file, "r");
+
+ /* Open dump file if requested */
+ if (dfile != NULL) {
+ dfp = open_file(dfile, "w");
+ }
+
+ x = y = xn = yn_ = NULL;
+ do {
+ /* We want to start anew for every matrix. */
+ maxnx = maxny = 0;
+ nx = maxnx; ny = maxny;
+ if (pr>0) lapTime = util_cpu_time();
+ if (harwell) {
+ if (pr >= 0) (void) printf(":name: ");
+ ok = Cudd_addHarwell(fp, dd, &M, &x, &y, &xn, &yn_, &nx, &ny,
+ &m, &n, 0, 2, 1, 2, pr);
+ } else {
+ ok = Cudd_addRead(fp, dd, &M, &x, &y, &xn, &yn_, &nx, &ny,
+ &m, &n, 0, 2, 1, 2);
+ if (pr >= 0)
+ (void) printf(":name: %s: %d rows %d columns\n", file, m, n);
+ }
+ if (!ok) {
+ (void) fprintf(stderr, "Error reading matrix\n");
+ exit(1);
+ }
+
+ if (nx > maxnx) maxnx = nx;
+ if (ny > maxny) maxny = ny;
+
+ /* Build cube of negated y's. */
+ ycube = DD_ONE(dd);
+ Cudd_Ref(ycube);
+ for (i = maxny - 1; i >= 0; i--) {
+ DdNode *tmpp;
+ tmpp = Cudd_bddAnd(dd,Cudd_Not(dd->vars[y[i]->index]),ycube);
+ if (tmpp == NULL) exit(2);
+ Cudd_Ref(tmpp);
+ Cudd_RecursiveDeref(dd,ycube);
+ ycube = tmpp;
+ }
+ /* Initialize vectors of BDD variables used by priority func. */
+ xvars = ALLOC(DdNode *, nx);
+ if (xvars == NULL) exit(2);
+ for (i = 0; i < nx; i++) {
+ xvars[i] = dd->vars[x[i]->index];
+ }
+ yvars = ALLOC(DdNode *, ny);
+ if (yvars == NULL) exit(2);
+ for (i = 0; i < ny; i++) {
+ yvars[i] = dd->vars[y[i]->index];
+ }
+
+ /* Clean up */
+ for (i=0; i < maxnx; i++) {
+ Cudd_RecursiveDeref(dd, x[i]);
+ Cudd_RecursiveDeref(dd, xn[i]);
+ }
+ FREE(x);
+ FREE(xn);
+ for (i=0; i < maxny; i++) {
+ Cudd_RecursiveDeref(dd, y[i]);
+ Cudd_RecursiveDeref(dd, yn_[i]);
+ }
+ FREE(y);
+ FREE(yn_);
+
+ if (pr>0) {(void) printf(":1: M"); Cudd_PrintDebug(dd,M,nx+ny,pr);}
+
+ if (pr>0) (void) printf(":2: time to read the matrix = %s\n",
+ util_print_time(util_cpu_time() - lapTime));
+
+ C = Cudd_addBddPattern(dd, M);
+ if (C == 0) exit(2);
+ Cudd_Ref(C);
+ if (pr>0) {(void) printf(":3: C"); Cudd_PrintDebug(dd,C,nx+ny,pr);}
+
+ /* Test iterators. */
+ retval = testIterators(dd,M,C,pr);
+ if (retval == 0) exit(2);
+
+ cuddCacheProfile(dd,stdout);
+
+ /* Test XOR */
+ retval = testXor(dd,C,pr,nx+ny);
+ if (retval == 0) exit(2);
+
+ /* Test Hamming distance functions. */
+ retval = testHamming(dd,C,pr,nx+ny);
+ if (retval == 0) exit(2);
+
+ /* Test selection functions. */
+ CP = Cudd_CProjection(dd,C,ycube);
+ if (CP == NULL) exit(2);
+ Cudd_Ref(CP);
+ if (pr>0) {(void) printf("ycube"); Cudd_PrintDebug(dd,ycube,nx+ny,pr);}
+ if (pr>0) {(void) printf("CP"); Cudd_PrintDebug(dd,CP,nx+ny,pr);}
+
+ if (nx == ny) {
+ CPr = Cudd_PrioritySelect(dd,C,xvars,yvars,(DdNode **)NULL,
+ (DdNode *)NULL,ny,Cudd_Xgty);
+ if (CPr == NULL) exit(2);
+ Cudd_Ref(CPr);
+ if (pr>0) {(void) printf(":4: CPr"); Cudd_PrintDebug(dd,CPr,nx+ny,pr);}
+ if (CP != CPr) {
+ (void) printf("CP != CPr!\n");
+ }
+ Cudd_RecursiveDeref(dd, CPr);
+ }
+ FREE(xvars); FREE(yvars);
+
+ Cudd_RecursiveDeref(dd, CP);
+ Cudd_RecursiveDeref(dd, ycube);
+
+ /* Test functions for essential variables. */
+ ess = Cudd_FindEssential(dd,C);
+ if (ess == NULL) exit(2);
+ Cudd_Ref(ess);
+ if (pr>0) {(void) printf(":4: ess"); Cudd_PrintDebug(dd,ess,nx+ny,pr);}
+ Cudd_RecursiveDeref(dd, ess);
+
+ /* Test functions for shortest paths. */
+ shortP = Cudd_ShortestPath(dd, M, NULL, NULL, &length);
+ if (shortP == NULL) exit(2);
+ Cudd_Ref(shortP);
+ if (pr>0) {
+ (void) printf(":5: shortP"); Cudd_PrintDebug(dd,shortP,nx+ny,pr);
+ }
+ /* Test functions for largest cubes. */
+ largest = Cudd_LargestCube(dd, Cudd_Not(C), &length);
+ if (largest == NULL) exit(2);
+ Cudd_Ref(largest);
+ if (pr>0) {
+ (void) printf(":5b: largest");
+ Cudd_PrintDebug(dd,largest,nx+ny,pr);
+ }
+ Cudd_RecursiveDeref(dd, largest);
+
+ /* Test Cudd_addEvalConst and Cudd_addIteConstant. */
+ shortA = Cudd_BddToAdd(dd,shortP);
+ if (shortA == NULL) exit(2);
+ Cudd_Ref(shortA);
+ Cudd_RecursiveDeref(dd, shortP);
+ constN = Cudd_addEvalConst(dd,shortA,M);
+ if (constN == DD_NON_CONSTANT) exit(2);
+ if (Cudd_addIteConstant(dd,shortA,M,constN) != constN) exit(2);
+ if (pr>0) {(void) printf("The value of M along the chosen shortest path is %g\n", cuddV(constN));}
+ Cudd_RecursiveDeref(dd, shortA);
+
+ shortP = Cudd_ShortestPath(dd, C, NULL, NULL, &length);
+ if (shortP == NULL) exit(2);
+ Cudd_Ref(shortP);
+ if (pr>0) {
+ (void) printf(":6: shortP"); Cudd_PrintDebug(dd,shortP,nx+ny,pr);
+ }
+
+ /* Test Cudd_bddIteConstant and Cudd_bddLeq. */
+ if (!Cudd_bddLeq(dd,shortP,C)) exit(2);
+ if (Cudd_bddIteConstant(dd,Cudd_Not(shortP),one,C) != one) exit(2);
+ Cudd_RecursiveDeref(dd, shortP);
+
+ if (profile) {
+ retval = cuddHeapProfile(dd);
+ }
+
+ size = dd->size;
+
+ if (pr>0) {
+ (void) printf("Average distance: %g\n", Cudd_AverageDistance(dd));
+ }
+
+ /* Reorder if so requested. */
+ if (approach != CUDD_REORDER_NONE) {
+#ifndef DD_STATS
+ retval = Cudd_EnableReorderingReporting(dd);
+ if (retval == 0) {
+ (void) fprintf(stderr,"Error reported by Cudd_EnableReorderingReporting\n");
+ exit(3);
+ }
+#endif
+#ifdef DD_DEBUG
+ retval = Cudd_DebugCheck(dd);
+ if (retval != 0) {
+ (void) fprintf(stderr,"Error reported by Cudd_DebugCheck\n");
+ exit(3);
+ }
+ retval = Cudd_CheckKeys(dd);
+ if (retval != 0) {
+ (void) fprintf(stderr,"Error reported by Cudd_CheckKeys\n");
+ exit(3);
+ }
+#endif
+ retval = Cudd_ReduceHeap(dd,(Cudd_ReorderingType)approach,5);
+ if (retval == 0) {
+ (void) fprintf(stderr,"Error reported by Cudd_ReduceHeap\n");
+ exit(3);
+ }
+#ifndef DD_STATS
+ retval = Cudd_DisableReorderingReporting(dd);
+ if (retval == 0) {
+ (void) fprintf(stderr,"Error reported by Cudd_DisableReorderingReporting\n");
+ exit(3);
+ }
+#endif
+#ifdef DD_DEBUG
+ retval = Cudd_DebugCheck(dd);
+ if (retval != 0) {
+ (void) fprintf(stderr,"Error reported by Cudd_DebugCheck\n");
+ exit(3);
+ }
+ retval = Cudd_CheckKeys(dd);
+ if (retval != 0) {
+ (void) fprintf(stderr,"Error reported by Cudd_CheckKeys\n");
+ exit(3);
+ }
+#endif
+ if (approach == CUDD_REORDER_SYMM_SIFT ||
+ approach == CUDD_REORDER_SYMM_SIFT_CONV) {
+ Cudd_SymmProfile(dd,0,dd->size-1);
+ }
+
+ if (pr>0) {
+ (void) printf("Average distance: %g\n", Cudd_AverageDistance(dd));
+ }
+
+ if (keepperm) {
+ /* Print variable permutation. */
+ (void) printf("Variable Permutation:");
+ for (i=0; i<size; i++) {
+ if (i%20 == 0) (void) printf("\n");
+ (void) printf("%d ", dd->invperm[i]);
+ }
+ (void) printf("\n");
+ (void) printf("Inverse Permutation:");
+ for (i=0; i<size; i++) {
+ if (i%20 == 0) (void) printf("\n");
+ (void) printf("%d ", dd->perm[i]);
+ }
+ (void) printf("\n");
+ }
+
+ if (pr>0) {(void) printf("M"); Cudd_PrintDebug(dd,M,nx+ny,pr);}
+
+ if (profile) {
+ retval = cuddHeapProfile(dd);
+ }
+
+ }
+
+ /* Dump DDs of C and M if so requested. */
+ if (dfile != NULL) {
+ dfunc[0] = C;
+ dfunc[1] = M;
+ if (blifOrDot == 1) {
+ /* Only dump C because blif cannot handle ADDs */
+ retval = Cudd_DumpBlif(dd,1,dfunc,NULL,onames,NULL,dfp);
+ } else {
+ retval = Cudd_DumpDot(dd,2,dfunc,NULL,onames,dfp);
+ }
+ if (retval != 1) {
+ (void) fprintf(stderr,"abnormal termination\n");
+ exit(2);
+ }
+ }
+
+ Cudd_RecursiveDeref(dd, C);
+ Cudd_RecursiveDeref(dd, M);
+
+ if (clearcache) {
+ if (pr>0) {(void) printf("Clearing the cache... ");}
+ for (i = dd->cacheSlots - 1; i>=0; i--) {
+ dd->cache[i].data = NIL(DdNode);
+ }
+ if (pr>0) {(void) printf("done\n");}
+ }
+ if (pr>0) {
+ (void) printf("Number of variables = %6d\t",dd->size);
+ (void) printf("Number of slots = %6d\n",dd->slots);
+ (void) printf("Number of keys = %6d\t",dd->keys);
+ (void) printf("Number of min dead = %6d\n",dd->minDead);
+ }
+
+ } while (multiple && !feof(fp));
+
+ fclose(fp);
+ if (dfile != NULL) {
+ fclose(dfp);
+ }
+
+ /* Second phase: experiment with Walsh matrices. */
+ if (!testWalsh(dd,N,cmu,approach,pr)) {
+ exit(2);
+ }
+
+ /* Check variable destruction. */
+ assert(cuddDestroySubtables(dd,3));
+ assert(Cudd_DebugCheck(dd) == 0);
+ assert(Cudd_CheckKeys(dd) == 0);
+
+ retval = Cudd_CheckZeroRef(dd);
+ ok = retval != 0; /* ok == 0 means O.K. */
+ if (retval != 0) {
+ (void) fprintf(stderr,
+ "%d non-zero DD reference counts after dereferencing\n", retval);
+ }
+
+ if (pr >= 0) {
+ (void) Cudd_PrintInfo(dd,stdout);
+ }
+
+ Cudd_Quit(dd);
+
+#ifdef MNEMOSYNE
+ mnem_writestats();
+#endif
+
+ if (pr>0) (void) printf("total time = %s\n",
+ util_print_time(util_cpu_time() - startTime));
+
+ if (pr >= 0) util_print_cpu_stats(stdout);
+ exit(ok);
+ /* NOTREACHED */
+
+} /* end of main */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints usage info for testcudd.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+usage(char *prog)
+{
+ (void) fprintf(stderr, "usage: %s [options] [file]\n", prog);
+ (void) fprintf(stderr, " -C\t\tuse CMU multiplication algorithm\n");
+ (void) fprintf(stderr, " -D\t\tenable automatic dynamic reordering\n");
+ (void) fprintf(stderr, " -H\t\tread matrix in Harwell format\n");
+ (void) fprintf(stderr, " -M\t\tturns off memory allocation recording\n");
+ (void) fprintf(stderr, " -P\t\tprint BDD heap profile\n");
+ (void) fprintf(stderr, " -S n\t\tnumber of slots for each subtable\n");
+ (void) fprintf(stderr, " -X n\t\ttarget maximum memory in bytes\n");
+ (void) fprintf(stderr, " -a n\t\tchoose reordering approach (0-13)\n");
+ (void) fprintf(stderr, " \t\t\t0: same as autoMethod\n");
+ (void) fprintf(stderr, " \t\t\t1: no reordering (default)\n");
+ (void) fprintf(stderr, " \t\t\t2: random\n");
+ (void) fprintf(stderr, " \t\t\t3: pivot\n");
+ (void) fprintf(stderr, " \t\t\t4: sifting\n");
+ (void) fprintf(stderr, " \t\t\t5: sifting to convergence\n");
+ (void) fprintf(stderr, " \t\t\t6: symmetric sifting\n");
+ (void) fprintf(stderr, " \t\t\t7: symmetric sifting to convergence\n");
+ (void) fprintf(stderr, " \t\t\t8-10: window of size 2-4\n");
+ (void) fprintf(stderr, " \t\t\t11-13: window of size 2-4 to conv.\n");
+ (void) fprintf(stderr, " \t\t\t14: group sifting\n");
+ (void) fprintf(stderr, " \t\t\t15: group sifting to convergence\n");
+ (void) fprintf(stderr, " \t\t\t16: simulated annealing\n");
+ (void) fprintf(stderr, " \t\t\t17: genetic algorithm\n");
+ (void) fprintf(stderr, " -b\t\tuse blif as format for dumps\n");
+ (void) fprintf(stderr, " -c\t\tclear the cache after each matrix\n");
+ (void) fprintf(stderr, " -d file\tdump DDs to file\n");
+ (void) fprintf(stderr, " -g\t\tselect aggregation criterion (0,5,7)\n");
+ (void) fprintf(stderr, " -h\t\tprints this message\n");
+ (void) fprintf(stderr, " -k\t\tprint the variable permutation\n");
+ (void) fprintf(stderr, " -m\t\tread multiple matrices (only with -H)\n");
+ (void) fprintf(stderr, " -n n\t\tnumber of variables\n");
+ (void) fprintf(stderr, " -p n\t\tcontrol verbosity\n");
+ (void) fprintf(stderr, " -v n\t\tinitial variables in the unique table\n");
+ (void) fprintf(stderr, " -x n\t\tinitial size of the cache\n");
+ exit(2);
+} /* end of usage */
+
+
+/**Function********************************************************************
+
+ Synopsis [Opens a file.]
+
+ Description [Opens a file, or fails with an error message and exits.
+ Allows '-' as a synonym for standard input.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static FILE *
+open_file(char *filename, char *mode)
+{
+ FILE *fp;
+
+ if (strcmp(filename, "-") == 0) {
+ return mode[0] == 'r' ? stdin : stdout;
+ } else if ((fp = fopen(filename, mode)) == NULL) {
+ perror(filename);
+ exit(1);
+ }
+ return fp;
+
+} /* end of open_file */
+
+
+/**Function********************************************************************
+
+ Synopsis [Tests Walsh matrix multiplication.]
+
+ Description [Tests Walsh matrix multiplication. Return 1 if successful;
+ 0 otherwise.]
+
+ SideEffects [May create new variables in the manager.]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+testWalsh(
+ DdManager *dd /* manager */,
+ int N /* number of variables */,
+ int cmu /* use CMU approach to matrix multiplication */,
+ int approach /* reordering approach */,
+ int pr /* verbosity level */)
+{
+ DdNode *walsh1, *walsh2, *wtw;
+ DdNode **x, **v, **z;
+ int i, retval;
+ DdNode *one = DD_ONE(dd);
+ DdNode *zero = DD_ZERO(dd);
+
+ if (N > 3) {
+ x = ALLOC(DdNode *,N);
+ v = ALLOC(DdNode *,N);
+ z = ALLOC(DdNode *,N);
+
+ for (i = N-1; i >= 0; i--) {
+ Cudd_Ref(x[i]=cuddUniqueInter(dd,3*i,one,zero));
+ Cudd_Ref(v[i]=cuddUniqueInter(dd,3*i+1,one,zero));
+ Cudd_Ref(z[i]=cuddUniqueInter(dd,3*i+2,one,zero));
+ }
+ Cudd_Ref(walsh1 = Cudd_addWalsh(dd,v,z,N));
+ if (pr>0) {(void) printf("walsh1"); Cudd_PrintDebug(dd,walsh1,2*N,pr);}
+ Cudd_Ref(walsh2 = Cudd_addWalsh(dd,x,v,N));
+ if (cmu) {
+ Cudd_Ref(wtw = Cudd_addTimesPlus(dd,walsh2,walsh1,v,N));
+ } else {
+ Cudd_Ref(wtw = Cudd_addMatrixMultiply(dd,walsh2,walsh1,v,N));
+ }
+ if (pr>0) {(void) printf("wtw"); Cudd_PrintDebug(dd,wtw,2*N,pr);}
+
+ if (approach != CUDD_REORDER_NONE) {
+#ifdef DD_DEBUG
+ retval = Cudd_DebugCheck(dd);
+ if (retval != 0) {
+ (void) fprintf(stderr,"Error reported by Cudd_DebugCheck\n");
+ return(0);
+ }
+#endif
+ retval = Cudd_ReduceHeap(dd,(Cudd_ReorderingType)approach,5);
+ if (retval == 0) {
+ (void) fprintf(stderr,"Error reported by Cudd_ReduceHeap\n");
+ return(0);
+ }
+#ifdef DD_DEBUG
+ retval = Cudd_DebugCheck(dd);
+ if (retval != 0) {
+ (void) fprintf(stderr,"Error reported by Cudd_DebugCheck\n");
+ return(0);
+ }
+#endif
+ if (approach == CUDD_REORDER_SYMM_SIFT ||
+ approach == CUDD_REORDER_SYMM_SIFT_CONV) {
+ Cudd_SymmProfile(dd,0,dd->size-1);
+ }
+ }
+ /* Clean up. */
+ Cudd_RecursiveDeref(dd, wtw);
+ Cudd_RecursiveDeref(dd, walsh1);
+ Cudd_RecursiveDeref(dd, walsh2);
+ for (i=0; i < N; i++) {
+ Cudd_RecursiveDeref(dd, x[i]);
+ Cudd_RecursiveDeref(dd, v[i]);
+ Cudd_RecursiveDeref(dd, z[i]);
+ }
+ FREE(x);
+ FREE(v);
+ FREE(z);
+ }
+ return(1);
+
+} /* end of testWalsh */
+
+/**Function********************************************************************
+
+ Synopsis [Tests iterators.]
+
+ Description [Tests iterators on cubes and nodes.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+testIterators(
+ DdManager *dd,
+ DdNode *M,
+ DdNode *C,
+ int pr)
+{
+ int *cube;
+ CUDD_VALUE_TYPE value;
+ DdGen *gen;
+ int q;
+
+ /* Test iterator for cubes. */
+ if (pr>1) {
+ (void) printf("Testing iterator on cubes:\n");
+ Cudd_ForeachCube(dd,M,gen,cube,value) {
+ for (q = 0; q < dd->size; q++) {
+ switch (cube[q]) {
+ case 0:
+ (void) printf("0");
+ break;
+ case 1:
+ (void) printf("1");
+ break;
+ case 2:
+ (void) printf("-");
+ break;
+ default:
+ (void) printf("?");
+ }
+ }
+ (void) printf(" %g\n",value);
+ }
+ (void) printf("\n");
+ }
+
+ if (pr>1) {
+ (void) printf("Testing prime expansion of cubes:\n");
+ if (!Cudd_bddPrintCover(dd,C,C)) return(0);
+ }
+
+ /* Test iterator on nodes. */
+ if (pr>2) {
+ DdGen *gen;
+ DdNode *node;
+ (void) printf("Testing iterator on nodes:\n");
+ Cudd_ForeachNode(dd,M,gen,node) {
+ if (Cudd_IsConstant(node)) {
+#if SIZEOF_VOID_P == 8
+ (void) printf("ID = 0x%lx\tvalue = %-9g\n",
+ (unsigned long) node /
+ (unsigned long) sizeof(DdNode),
+ Cudd_V(node));
+#else
+ (void) printf("ID = 0x%x\tvalue = %-9g\n",
+ (unsigned int) node /
+ (unsigned int) sizeof(DdNode),
+ Cudd_V(node));
+#endif
+ } else {
+#if SIZEOF_VOID_P == 8
+ (void) printf("ID = 0x%lx\tindex = %d\tr = %d\n",
+ (unsigned long) node /
+ (unsigned long) sizeof(DdNode),
+ node->index, node->ref);
+#else
+ (void) printf("ID = 0x%x\tindex = %d\tr = %d\n",
+ (unsigned int) node /
+ (unsigned int) sizeof(DdNode),
+ node->index, node->ref);
+#endif
+ }
+ }
+ (void) printf("\n");
+ }
+ return(1);
+
+} /* end of testIterators */
+
+
+/**Function********************************************************************
+
+ Synopsis [Tests the functions related to the exclusive OR.]
+
+ Description [Tests the functions related to the exclusive OR. It
+ builds the boolean difference of the given function in three
+ different ways and checks that the results is the same. Returns 1 if
+ successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+testXor(DdManager *dd, DdNode *f, int pr, int nvars)
+{
+ DdNode *f1, *f0, *res1, *res2;
+ int x;
+
+ /* Extract cofactors w.r.t. mid variable. */
+ x = nvars / 2;
+ f1 = Cudd_Cofactor(dd,f,dd->vars[x]);
+ if (f1 == NULL) return(0);
+ Cudd_Ref(f1);
+
+ f0 = Cudd_Cofactor(dd,f,Cudd_Not(dd->vars[x]));
+ if (f0 == NULL) {
+ Cudd_RecursiveDeref(dd,f1);
+ return(0);
+ }
+ Cudd_Ref(f0);
+
+ /* Compute XOR of cofactors with ITE. */
+ res1 = Cudd_bddIte(dd,f1,Cudd_Not(f0),f0);
+ if (res1 == NULL) return(0);
+ Cudd_Ref(res1);
+
+ if (pr>0) {(void) printf("xor1"); Cudd_PrintDebug(dd,res1,nvars,pr);}
+
+ /* Compute XOR of cofactors with XOR. */
+ res2 = Cudd_bddXor(dd,f1,f0);
+ if (res2 == NULL) {
+ Cudd_RecursiveDeref(dd,res1);
+ return(0);
+ }
+ Cudd_Ref(res2);
+
+ if (res1 != res2) {
+ if (pr>0) {(void) printf("xor2"); Cudd_PrintDebug(dd,res2,nvars,pr);}
+ Cudd_RecursiveDeref(dd,res1);
+ Cudd_RecursiveDeref(dd,res2);
+ return(0);
+ }
+ Cudd_RecursiveDeref(dd,res1);
+ Cudd_RecursiveDeref(dd,f1);
+ Cudd_RecursiveDeref(dd,f0);
+
+ /* Compute boolean difference directly. */
+ res1 = Cudd_bddBooleanDiff(dd,f,x);
+ if (res1 == NULL) {
+ Cudd_RecursiveDeref(dd,res2);
+ return(0);
+ }
+ Cudd_Ref(res1);
+
+ if (res1 != res2) {
+ if (pr>0) {(void) printf("xor3"); Cudd_PrintDebug(dd,res1,nvars,pr);}
+ Cudd_RecursiveDeref(dd,res1);
+ Cudd_RecursiveDeref(dd,res2);
+ return(0);
+ }
+ Cudd_RecursiveDeref(dd,res1);
+ Cudd_RecursiveDeref(dd,res2);
+ return(1);
+
+} /* end of testXor */
+
+
+/**Function********************************************************************
+
+ Synopsis [Tests the Hamming distance functions.]
+
+ Description [Tests the Hammming distance functions. Returns
+ 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+testHamming(
+ DdManager *dd,
+ DdNode *f,
+ int pr,
+ int nvars)
+{
+ DdNode **vars, *minBdd, *zero, *scan;
+ int i;
+ int d;
+ int *minterm;
+ int size = Cudd_ReadSize(dd);
+
+ vars = ALLOC(DdNode *, size);
+ if (vars == NULL) return(0);
+ for (i = 0; i < size; i++) {
+ vars[i] = Cudd_bddIthVar(dd,i);
+ }
+
+ minBdd = Cudd_bddPickOneMinterm(dd,Cudd_Not(f),vars,size);
+ Cudd_Ref(minBdd);
+ if (pr > 0) {
+ (void) printf("Chosen minterm for Hamming distance test: ");
+ Cudd_PrintDebug(dd,minBdd,size,pr);
+ }
+
+ minterm = ALLOC(int,size);
+ if (minterm == NULL) {
+ FREE(vars);
+ Cudd_RecursiveDeref(dd,minBdd);
+ return(0);
+ }
+ scan = minBdd;
+ zero = Cudd_Not(DD_ONE(dd));
+ while (!Cudd_IsConstant(scan)) {
+ DdNode *R = Cudd_Regular(scan);
+ DdNode *T = Cudd_T(R);
+ DdNode *E = Cudd_E(R);
+ if (R != scan) {
+ T = Cudd_Not(T);
+ E = Cudd_Not(E);
+ }
+ if (T == zero) {
+ minterm[R->index] = 0;
+ scan = E;
+ } else {
+ minterm[R->index] = 1;
+ scan = T;
+ }
+ }
+ Cudd_RecursiveDeref(dd,minBdd);
+
+ d = Cudd_MinHammingDist(dd,f,minterm,size);
+
+ (void) printf("Minimum Hamming distance = %d\n", d);
+
+ FREE(vars);
+ FREE(minterm);
+ return(1);
+
+} /* end of testHamming */
diff --git a/src/bdd/dsd/dsd.h b/src/bdd/dsd/dsd.h
new file mode 100644
index 00000000..60cf4a4e
--- /dev/null
+++ b/src/bdd/dsd/dsd.h
@@ -0,0 +1,115 @@
+/**CFile****************************************************************
+
+ FileName [dsd.h]
+
+ PackageName [DSD: Disjoint-support decomposition package.]
+
+ Synopsis [External declarations of the package.
+ This fast BDD-based recursive algorithm for simple
+ (single-output) DSD is based on the following papers:
+ (1) V. Bertacco and M. Damiani, "Disjunctive decomposition of
+ logic functions," Proc. ICCAD '97, pp. 78-82.
+ (2) Y. Matsunaga, "An exact and efficient algorithm for disjunctive
+ decomposition", Proc. SASIMI '98, pp. 44-50.
+ The scope of detected decompositions is the same as in the paper:
+ T. Sasao and M. Matsuura, "DECOMPOS: An integrated system for
+ functional decomposition," Proc. IWLS '98, pp. 471-477.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 8.0. Started - September 22, 2003.]
+
+ Revision [$Id: dsd.h,v 1.0 2002/22/09 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __DSD_H__
+#define __DSD_H__
+
+////////////////////////////////////////////////////////////////////////
+/// TYPEDEF DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+typedef struct Dsd_Manager_t_ Dsd_Manager_t;
+typedef struct Dsd_Node_t_ Dsd_Node_t;
+typedef enum Dsd_Type_t_ Dsd_Type_t;
+
+////////////////////////////////////////////////////////////////////////
+/// STRUCTURE DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+// types of DSD nodes
+enum Dsd_Type_t_ {
+ DSD_NODE_NONE = 0,
+ DSD_NODE_CONST1 = 1,
+ DSD_NODE_BUF = 2,
+ DSD_NODE_OR = 3,
+ DSD_NODE_EXOR = 4,
+ DSD_NODE_PRIME = 5,
+};
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// complementation and testing for pointers for decomposition entries
+#define Dsd_IsComplement(p) (((int)((long) (p) & 01)))
+#define Dsd_Regular(p) ((Dsd_Node_t *)((unsigned)(p) & ~01))
+#define Dsd_Not(p) ((Dsd_Node_t *)((long)(p) ^ 01))
+#define Dsd_NotCond(p,c) ((Dsd_Node_t *)((long)(p) ^ (c)))
+
+////////////////////////////////////////////////////////////////////////
+/// ITERATORS ///
+////////////////////////////////////////////////////////////////////////
+
+// iterator through the transitions
+#define Dsd_NodeForEachChild( Node, Index, Child ) \
+ for ( Index = 0; \
+ Index < Dsd_NodeReadDecsNum(Node) && \
+ ((Child = Dsd_NodeReadDec(Node,Index))>=0); \
+ Index++ )
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*=== dsdApi.c =======================================================*/
+extern Dsd_Type_t Dsd_NodeReadType( Dsd_Node_t * p );
+extern DdNode * Dsd_NodeReadFunc( Dsd_Node_t * p );
+extern DdNode * Dsd_NodeReadSupp( Dsd_Node_t * p );
+extern Dsd_Node_t ** Dsd_NodeReadDecs( Dsd_Node_t * p );
+extern Dsd_Node_t * Dsd_NodeReadDec ( Dsd_Node_t * p, int i );
+extern int Dsd_NodeReadDecsNum( Dsd_Node_t * p );
+extern int Dsd_NodeReadMark( Dsd_Node_t * p );
+extern void Dsd_NodeSetMark( Dsd_Node_t * p, int Mark );
+extern Dsd_Node_t * Dsd_ManagerReadRoot( Dsd_Manager_t * pMan, int i );
+extern Dsd_Node_t * Dsd_ManagerReadInput( Dsd_Manager_t * pMan, int i );
+/*=== dsdMan.c =======================================================*/
+extern Dsd_Manager_t * Dsd_ManagerStart( DdManager * dd, int nSuppMax, int fVerbose );
+extern void Dsd_ManagerStop( Dsd_Manager_t * dMan );
+/*=== dsdProc.c =======================================================*/
+extern void Dsd_Decompose( Dsd_Manager_t * dMan, DdNode ** pbFuncs, int nFuncs );
+/*=== dsdTree.c =======================================================*/
+extern void Dsd_TreeNodeGetInfo( Dsd_Manager_t * dMan, int * DepthMax, int * GateSizeMax );
+extern void Dsd_TreeNodeGetInfoOne( Dsd_Node_t * pNode, int * DepthMax, int * GateSizeMax );
+extern int Dsd_TreeCountNonTerminalNodes( Dsd_Manager_t * dMan );
+extern int Dsd_TreeCountNonTerminalNodesOne( Dsd_Node_t * pRoot );
+extern int Dsd_TreeCountPrimeNodes( Dsd_Manager_t * pDsdMan );
+extern int Dsd_TreeCountPrimeNodesOne( Dsd_Node_t * pRoot );
+extern int Dsd_TreeCollectDecomposableVars( Dsd_Manager_t * dMan, int * pVars );
+extern Dsd_Node_t ** Dsd_TreeCollectNodesDfs( Dsd_Manager_t * dMan, int * pnNodes );
+extern void Dsd_TreePrint( FILE * pFile, Dsd_Manager_t * dMan, char * pInputNames[], char * pOutputNames[], int fShortNames, int Output );
+/*=== dsdLocal.c =======================================================*/
+extern DdNode * Dsd_TreeGetPrimeFunction( DdManager * dd, Dsd_Node_t * pNode );
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+#endif \ No newline at end of file
diff --git a/src/bdd/dsd/dsdApi.c b/src/bdd/dsd/dsdApi.c
new file mode 100644
index 00000000..f2269092
--- /dev/null
+++ b/src/bdd/dsd/dsdApi.c
@@ -0,0 +1,95 @@
+/**CFile****************************************************************
+
+ FileName [dsdApi.c]
+
+ PackageName [DSD: Disjoint-support decomposition package.]
+
+ Synopsis [Implementation of API functions.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 8.0. Started - September 22, 2003.]
+
+ Revision [$Id: dsdApi.c,v 1.0 2002/22/09 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "dsdInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [APIs of the DSD node.]
+
+ Description [The node's type can be retrieved by calling
+ Dsd_NodeReadType(). The type is one of the following: constant 1 node,
+ the buffer (or the elementary variable), OR gate, EXOR gate, or
+ PRIME function (a non-DSD-decomposable function with more than two
+ inputs). The return value of Dsd_NodeReadFunc() is the global function
+ of the DSD node. The return value of Dsd_NodeReadSupp() is the support
+ of the global function of the DSD node. The array of DSD nodes
+ returned by Dsd_NodeReadDecs() is the array of decomposition nodes for
+ the formal inputs of the given node. The number of decomposition entries
+ returned by Dsd_NodeReadDecsNum() is the number of formal inputs.
+ The mark is explained below.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Dsd_Type_t Dsd_NodeReadType( Dsd_Node_t * p ) { return p->Type; }
+DdNode * Dsd_NodeReadFunc( Dsd_Node_t * p ) { return p->G; }
+DdNode * Dsd_NodeReadSupp( Dsd_Node_t * p ) { return p->S; }
+Dsd_Node_t ** Dsd_NodeReadDecs( Dsd_Node_t * p ) { return p->pDecs; }
+Dsd_Node_t * Dsd_NodeReadDec ( Dsd_Node_t * p, int i ) { return p->pDecs[i]; }
+int Dsd_NodeReadDecsNum( Dsd_Node_t * p ) { return p->nDecs; }
+int Dsd_NodeReadMark( Dsd_Node_t * p ) { return p->Mark; }
+
+/**Function*************************************************************
+
+ Synopsis [APIs of the DSD node.]
+
+ Description [This API allows the user to set the integer mark in the
+ given DSD node. The mark is guaranteed to persist as long as the
+ calls to the decomposition are not performed. In any case, the mark
+ is useful to associate the node with some temporary information, such
+ as its number in the DFS ordered list of the DSD nodes or its number in
+ the BLIF file that it being written.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Dsd_NodeSetMark( Dsd_Node_t * p, int Mark ){ p->Mark = Mark; }
+
+/**Function*************************************************************
+
+ Synopsis [APIs of the DSD manager.]
+
+ Description [Allows the use to get hold of an individual leave of
+ the DSD tree (Dsd_ManagerReadInput) or an individual root of the
+ decomposition tree (Dsd_ManagerReadRoot). The root may have the
+ complemented attribute.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Dsd_Node_t * Dsd_ManagerReadRoot( Dsd_Manager_t * pMan, int i ) { return pMan->pRoots[i]; }
+Dsd_Node_t * Dsd_ManagerReadInput( Dsd_Manager_t * pMan, int i ) { return pMan->pInputs[i]; }
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
diff --git a/src/bdd/dsd/dsdCheck.c b/src/bdd/dsd/dsdCheck.c
new file mode 100644
index 00000000..608aa2e3
--- /dev/null
+++ b/src/bdd/dsd/dsdCheck.c
@@ -0,0 +1,314 @@
+/**CFile****************************************************************
+
+ FileName [dsdCheck.c]
+
+ PackageName [DSD: Disjoint-support decomposition package.]
+
+ Synopsis [Procedures to check the identity of root functions.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 8.0. Started - September 22, 2003.]
+
+ Revision [$Id: dsdCheck.c,v 1.0 2002/22/09 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "dsdInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+typedef struct Dsd_Cache_t_ Dds_Cache_t;
+typedef struct Dsd_Entry_t_ Dsd_Entry_t;
+
+struct Dsd_Cache_t_
+{
+ Dsd_Entry_t * pTable;
+ int nTableSize;
+ int nSuccess;
+ int nFailure;
+};
+
+struct Dsd_Entry_t_
+{
+ DdNode * bX[5];
+};
+
+static Dds_Cache_t * pCache;
+
+static int Dsd_CheckRootFunctionIdentity_rec( DdManager * dd, DdNode * bF1, DdNode * bF2, DdNode * bC1, DdNode * bC2 );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function********************************************************************
+
+ Synopsis [(Re)allocates the local cache.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void Dsd_CheckCacheAllocate( int nEntries )
+{
+ int nRequested;
+
+ pCache = ALLOC( Dds_Cache_t, 1 );
+ memset( pCache, 0, sizeof(Dds_Cache_t) );
+
+ // check what is the size of the current cache
+ nRequested = Cudd_Prime( nEntries );
+ if ( pCache->nTableSize != nRequested )
+ { // the current size is different
+ // deallocate the old, allocate the new
+ if ( pCache->nTableSize )
+ Dsd_CheckCacheDeallocate();
+ // allocate memory for the hash table
+ pCache->nTableSize = nRequested;
+ pCache->pTable = ALLOC( Dsd_Entry_t, nRequested );
+ }
+ // otherwise, there is no need to allocate, just clean
+ Dsd_CheckCacheClear();
+// printf( "\nThe number of allocated cache entries = %d.\n\n", pCache->nTableSize );
+}
+
+/**Function********************************************************************
+
+ Synopsis [Delocates the local cache.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void Dsd_CheckCacheDeallocate()
+{
+ free( pCache->pTable );
+ free( pCache );
+}
+
+/**Function********************************************************************
+
+ Synopsis [Clears the local cache.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void Dsd_CheckCacheClear()
+{
+ int i;
+ for ( i = 0; i < pCache->nTableSize; i++ )
+ pCache->pTable[0].bX[0] = NULL;
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether it is true that bF1(bC1=0) == bF2(bC2=0).]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int Dsd_CheckRootFunctionIdentity( DdManager * dd, DdNode * bF1, DdNode * bF2, DdNode * bC1, DdNode * bC2 )
+{
+ int RetValue;
+// pCache->nSuccess = 0;
+// pCache->nFailure = 0;
+ RetValue = Dsd_CheckRootFunctionIdentity_rec(dd, bF1, bF2, bC1, bC2);
+// printf( "Cache success = %d. Cache failure = %d.\n", pCache->nSuccess, pCache->nFailure );
+ return RetValue;
+}
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Dsd_CheckRootFunctionIdentity().]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int Dsd_CheckRootFunctionIdentity_rec( DdManager * dd, DdNode * bF1, DdNode * bF2, DdNode * bC1, DdNode * bC2 )
+{
+ unsigned HKey;
+
+ // if either bC1 or bC2 is zero, the test is true
+// if ( bC1 == b0 || bC2 == b0 ) return 1;
+ assert( bC1 != b0 );
+ assert( bC2 != b0 );
+
+ // if both bC1 and bC2 are one - perform comparison
+ if ( bC1 == b1 && bC2 == b1 ) return (int)( bF1 == bF2 );
+
+ if ( bF1 == b0 )
+ return Cudd_bddLeq( dd, bC2, Cudd_Not(bF2) );
+
+ if ( bF1 == b1 )
+ return Cudd_bddLeq( dd, bC2, bF2 );
+
+ if ( bF2 == b0 )
+ return Cudd_bddLeq( dd, bC1, Cudd_Not(bF1) );
+
+ if ( bF2 == b1 )
+ return Cudd_bddLeq( dd, bC1, bF1 );
+
+ // otherwise, keep expanding
+
+ // check cache
+// HKey = _Hash( ((unsigned)bF1), ((unsigned)bF2), ((unsigned)bC1), ((unsigned)bC2) );
+ HKey = hashKey4( bF1, bF2, bC1, bC2, pCache->nTableSize );
+ if ( pCache->pTable[HKey].bX[0] == bF1 &&
+ pCache->pTable[HKey].bX[1] == bF2 &&
+ pCache->pTable[HKey].bX[2] == bC1 &&
+ pCache->pTable[HKey].bX[3] == bC2 )
+ {
+ pCache->nSuccess++;
+ return (int)pCache->pTable[HKey].bX[4]; // the last bit records the result (yes/no)
+ }
+ else
+ {
+
+ // determine the top variables
+ int RetValue;
+ DdNode * bA[4] = { bF1, bF2, bC1, bC2 }; // arguments
+ DdNode * bAR[4] = { Cudd_Regular(bF1), Cudd_Regular(bF2), Cudd_Regular(bC1), Cudd_Regular(bC2) }; // regular arguments
+ int CurLevel[4] = { cuddI(dd,bAR[0]->index), cuddI(dd,bAR[1]->index), cuddI(dd,bAR[2]->index), cuddI(dd,bAR[3]->index) };
+ int TopLevel = CUDD_CONST_INDEX;
+ int i;
+ DdNode * bE[4], * bT[4];
+ DdNode * bF1next, * bF2next, * bC1next, * bC2next;
+
+ pCache->nFailure++;
+
+ // determine the top level
+ for ( i = 0; i < 4; i++ )
+ if ( TopLevel > CurLevel[i] )
+ TopLevel = CurLevel[i];
+
+ // compute the cofactors
+ for ( i = 0; i < 4; i++ )
+ if ( TopLevel == CurLevel[i] )
+ {
+ if ( bA[i] != bAR[i] ) // complemented
+ {
+ bE[i] = Cudd_Not(cuddE(bAR[i]));
+ bT[i] = Cudd_Not(cuddT(bAR[i]));
+ }
+ else
+ {
+ bE[i] = cuddE(bAR[i]);
+ bT[i] = cuddT(bAR[i]);
+ }
+ }
+ else
+ bE[i] = bT[i] = bA[i];
+
+ // solve subproblems
+ // three cases are possible
+
+ // (1) the top var belongs to both C1 and C2
+ // in this case, any cofactor of F1 and F2 will do,
+ // as long as the corresponding cofactor of C1 and C2 is not equal to 0
+ if ( TopLevel == CurLevel[2] && TopLevel == CurLevel[3] )
+ {
+ if ( bE[2] != b0 ) // C1
+ {
+ bF1next = bE[0];
+ bC1next = bE[2];
+ }
+ else
+ {
+ bF1next = bT[0];
+ bC1next = bT[2];
+ }
+ if ( bE[3] != b0 ) // C2
+ {
+ bF2next = bE[1];
+ bC2next = bE[3];
+ }
+ else
+ {
+ bF2next = bT[1];
+ bC2next = bT[3];
+ }
+ RetValue = Dsd_CheckRootFunctionIdentity_rec( dd, bF1next, bF2next, bC1next, bC2next );
+ }
+ // (2) the top var belongs to either C1 or C2
+ // in this case normal splitting of cofactors
+ else if ( TopLevel == CurLevel[2] && TopLevel != CurLevel[3] )
+ {
+ if ( bE[2] != b0 ) // C1
+ {
+ bF1next = bE[0];
+ bC1next = bE[2];
+ }
+ else
+ {
+ bF1next = bT[0];
+ bC1next = bT[2];
+ }
+ // split around this variable
+ RetValue = Dsd_CheckRootFunctionIdentity_rec( dd, bF1next, bE[1], bC1next, bE[3] );
+ if ( RetValue == 1 ) // test another branch; otherwise, there is no need to test
+ RetValue = Dsd_CheckRootFunctionIdentity_rec( dd, bF1next, bT[1], bC1next, bT[3] );
+ }
+ else if ( TopLevel != CurLevel[2] && TopLevel == CurLevel[3] )
+ {
+ if ( bE[3] != b0 ) // C2
+ {
+ bF2next = bE[1];
+ bC2next = bE[3];
+ }
+ else
+ {
+ bF2next = bT[1];
+ bC2next = bT[3];
+ }
+ // split around this variable
+ RetValue = Dsd_CheckRootFunctionIdentity_rec( dd, bE[0], bF2next, bE[2], bC2next );
+ if ( RetValue == 1 ) // test another branch; otherwise, there is no need to test
+ RetValue = Dsd_CheckRootFunctionIdentity_rec( dd, bT[0], bF2next, bT[2], bC2next );
+ }
+ // (3) the top var does not belong to C1 and C2
+ // in this case normal splitting of cofactors
+ else // if ( TopLevel != CurLevel[2] && TopLevel != CurLevel[3] )
+ {
+ // split around this variable
+ RetValue = Dsd_CheckRootFunctionIdentity_rec( dd, bE[0], bE[1], bE[2], bE[3] );
+ if ( RetValue == 1 ) // test another branch; otherwise, there is no need to test
+ RetValue = Dsd_CheckRootFunctionIdentity_rec( dd, bT[0], bT[1], bT[2], bT[3] );
+ }
+
+ // set cache
+ for ( i = 0; i < 4; i++ )
+ pCache->pTable[HKey].bX[i] = bA[i];
+ pCache->pTable[HKey].bX[4] = (DdNode*)RetValue;
+
+ return RetValue;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
diff --git a/src/bdd/dsd/dsdInt.h b/src/bdd/dsd/dsdInt.h
new file mode 100644
index 00000000..81440460
--- /dev/null
+++ b/src/bdd/dsd/dsdInt.h
@@ -0,0 +1,88 @@
+/**CFile****************************************************************
+
+ FileName [dsdInt.h]
+
+ PackageName [DSD: Disjoint-support decomposition package.]
+
+ Synopsis [Internal declarations of the package.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 8.0. Started - September 22, 2003.]
+
+ Revision [$Id: dsdInt.h,v 1.0 2002/22/09 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __DSD_INT_H__
+#define __DSD_INT_H__
+
+#include "extra.h"
+#include "dsd.h"
+
+////////////////////////////////////////////////////////////////////////
+/// TYPEDEF DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+typedef unsigned char byte;
+
+////////////////////////////////////////////////////////////////////////
+/// STRUCTURE DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// DSD manager
+struct Dsd_Manager_t_
+{
+ DdManager * dd; // the BDD manager
+ st_table * Table; // the mapping of BDDs into their DEs
+ int nInputs; // the number of primary inputs
+ int nRoots; // the number of primary outputs
+ int nRootsAlloc;// the number of primary outputs
+ Dsd_Node_t ** pInputs; // the primary input nodes
+ Dsd_Node_t ** pRoots; // the primary output nodes
+ int fVerbose; // the verbosity level
+};
+
+// DSD node
+struct Dsd_Node_t_
+{
+ Dsd_Type_t Type; // decomposition type
+ DdNode * G; // function of the node
+ DdNode * S; // support of this function
+ Dsd_Node_t ** pDecs; // pointer to structures for formal inputs
+ int Mark; // the mark used by CASE 4 of disjoint decomposition
+ short nDecs; // the number of formal inputs
+ short nVisits; // the counter of visits
+};
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*=== dsdCheck.c =======================================================*/
+extern void Dsd_CheckCacheAllocate( int nEntries );
+extern void Dsd_CheckCacheDeallocate();
+extern void Dsd_CheckCacheClear();
+extern int Dsd_CheckRootFunctionIdentity( DdManager * dd, DdNode * bF1, DdNode * bF2, DdNode * bC1, DdNode * bC2 );
+/*=== dsdTree.c =======================================================*/
+extern Dsd_Node_t * Dsd_TreeNodeCreate( int Type, int nDecs, int BlockNum );
+extern void Dsd_TreeNodeDelete( DdManager * dd, Dsd_Node_t * pNode );
+extern void Dsd_TreeUnmark( Dsd_Manager_t * dMan );
+extern DdNode * Dsd_TreeGetPrimeFunctionOld( DdManager * dd, Dsd_Node_t * pNode, int fRemap );
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
+#endif \ No newline at end of file
diff --git a/src/bdd/dsd/dsdLocal.c b/src/bdd/dsd/dsdLocal.c
new file mode 100644
index 00000000..6dd6e7d1
--- /dev/null
+++ b/src/bdd/dsd/dsdLocal.c
@@ -0,0 +1,337 @@
+/**CFile****************************************************************
+
+ FileName [dsdLocal.c]
+
+ PackageName [DSD: Disjoint-support decomposition package.]
+
+ Synopsis [Deriving the local function of the DSD node.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 8.0. Started - September 22, 2003.]
+
+ Revision [$Id: dsdLocal.c,v 1.0 2002/22/09 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "dsdInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// STATIC VARIABLES ///
+////////////////////////////////////////////////////////////////////////
+
+static DdNode * Extra_dsdRemap( DdManager * dd, DdNode * bFunc, st_table * pCache,
+ int * pVar2Form, int * pForm2Var, DdNode * pbCube0[], DdNode * pbCube1[] );
+static DdNode * Extra_bddNodePointedByCube( DdManager * dd, DdNode * bF, DdNode * bC );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Returns the local function of the DSD node. ]
+
+ Description [The local function is computed using the global function
+ of the node and the global functions of the formal inputs. The resulting
+ local function is mapped using the topmost N variables of the manager.
+ The number of variables N is equal to the number of formal inputs.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdNode * Dsd_TreeGetPrimeFunction( DdManager * dd, Dsd_Node_t * pNode )
+{
+ int * pForm2Var; // the mapping of each formal input into its first var
+ int * pVar2Form; // the mapping of each var into its formal inputs
+ int i, iVar, iLev, * pPermute;
+ DdNode ** pbCube0, ** pbCube1;
+ DdNode * bFunc, * bRes, * bTemp;
+ st_table * pCache;
+
+ pPermute = ALLOC( int, dd->size );
+ pVar2Form = ALLOC( int, dd->size );
+ pForm2Var = ALLOC( int, dd->size );
+
+ pbCube0 = ALLOC( DdNode *, dd->size );
+ pbCube1 = ALLOC( DdNode *, dd->size );
+
+ // remap the global function in such a way that
+ // the support variables of each formal input are adjacent
+ iLev = 0;
+ for ( i = 0; i < pNode->nDecs; i++ )
+ {
+ pForm2Var[i] = dd->invperm[i];
+ for ( bTemp = pNode->pDecs[i]->S; bTemp != b1; bTemp = cuddT(bTemp) )
+ {
+ iVar = dd->invperm[iLev];
+ pPermute[bTemp->index] = iVar;
+ pVar2Form[iVar] = i;
+ iLev++;
+ }
+
+ // collect the cubes representing each assignment
+ pbCube0[i] = Extra_bddGetOneCube( dd, Cudd_Not(pNode->pDecs[i]->G) );
+ Cudd_Ref( pbCube0[i] );
+ pbCube1[i] = Extra_bddGetOneCube( dd, pNode->pDecs[i]->G );
+ Cudd_Ref( pbCube1[i] );
+ }
+
+ // remap the function
+ bFunc = Cudd_bddPermute( dd, pNode->G, pPermute ); Cudd_Ref( bFunc );
+ // remap the cube
+ for ( i = 0; i < pNode->nDecs; i++ )
+ {
+ pbCube0[i] = Cudd_bddPermute( dd, bTemp = pbCube0[i], pPermute ); Cudd_Ref( pbCube0[i] );
+ Cudd_RecursiveDeref( dd, bTemp );
+ pbCube1[i] = Cudd_bddPermute( dd, bTemp = pbCube1[i], pPermute ); Cudd_Ref( pbCube1[i] );
+ Cudd_RecursiveDeref( dd, bTemp );
+ }
+
+ // remap the function
+ pCache = st_init_table(st_ptrcmp,st_ptrhash);
+ bRes = Extra_dsdRemap( dd, bFunc, pCache, pVar2Form, pForm2Var, pbCube0, pbCube1 ); Cudd_Ref( bRes );
+ st_free_table( pCache );
+
+ Cudd_RecursiveDeref( dd, bFunc );
+ for ( i = 0; i < pNode->nDecs; i++ )
+ {
+ Cudd_RecursiveDeref( dd, pbCube0[i] );
+ Cudd_RecursiveDeref( dd, pbCube1[i] );
+ }
+/*
+////////////
+ // permute the function once again
+ // in such a way that i-th var stood for i-th formal input
+ for ( i = 0; i < dd->size; i++ )
+ pPermute[i] = -1;
+ for ( i = 0; i < pNode->nDecs; i++ )
+ pPermute[dd->invperm[i]] = i;
+ bRes = Cudd_bddPermute( dd, bTemp = bRes, pPermute ); Cudd_Ref( bRes );
+ Cudd_RecursiveDeref( dd, bTemp );
+////////////
+*/
+ FREE(pPermute);
+ FREE(pVar2Form);
+ FREE(pForm2Var);
+ FREE(pbCube0);
+ FREE(pbCube1);
+
+ Cudd_Deref( bRes );
+ return bRes;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdNode * Extra_dsdRemap( DdManager * dd, DdNode * bF, st_table * pCache,
+ int * pVar2Form, int * pForm2Var, DdNode * pbCube0[], DdNode * pbCube1[] )
+{
+ DdNode * bFR, * bF0, * bF1;
+ DdNode * bRes0, * bRes1, * bRes;
+ int iForm;
+
+ bFR = Cudd_Regular(bF);
+ if ( cuddIsConstant(bFR) )
+ return bF;
+
+ // check the hash-table
+ if ( bFR->ref != 1 )
+ {
+ if ( st_lookup( pCache, (char *)bF, (char **)&bRes ) )
+ return bRes;
+ }
+
+ // get the formal input
+ iForm = pVar2Form[bFR->index];
+
+ // get the nodes pointed to by the cube
+ bF0 = Extra_bddNodePointedByCube( dd, bF, pbCube0[iForm] );
+ bF1 = Extra_bddNodePointedByCube( dd, bF, pbCube1[iForm] );
+
+ // call recursively for these nodes
+ bRes0 = Extra_dsdRemap( dd, bF0, pCache, pVar2Form, pForm2Var, pbCube0, pbCube1 ); Cudd_Ref( bRes0 );
+ bRes1 = Extra_dsdRemap( dd, bF1, pCache, pVar2Form, pForm2Var, pbCube0, pbCube1 ); Cudd_Ref( bRes1 );
+
+ // derive the result using ITE
+ bRes = Cudd_bddIte( dd, dd->vars[ pForm2Var[iForm] ], bRes1, bRes0 ); Cudd_Ref( bRes );
+ Cudd_RecursiveDeref( dd, bRes0 );
+ Cudd_RecursiveDeref( dd, bRes1 );
+
+ // add to the hash table
+ if ( bFR->ref != 1 )
+ st_insert( pCache, (char *)bF, (char *)bRes );
+ Cudd_Deref( bRes );
+ return bRes;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdNode * Extra_bddNodePointedByCube( DdManager * dd, DdNode * bF, DdNode * bC )
+{
+ DdNode * bFR, * bCR;
+ DdNode * bF0, * bF1;
+ DdNode * bC0, * bC1;
+ int LevelF, LevelC;
+
+ assert( bC != b0 );
+ if ( bC == b1 )
+ return bF;
+
+// bRes = cuddCacheLookup2( dd, Extra_bddNodePointedByCube, bF, bC );
+// if ( bRes )
+// return bRes;
+ // there is no need for caching because this operation is very fast
+ // there will no gain reusing the results of this operations
+ // instead, it will flush CUDD cache of other useful entries
+
+
+ bFR = Cudd_Regular( bF );
+ bCR = Cudd_Regular( bC );
+ assert( !cuddIsConstant( bFR ) );
+
+ LevelF = dd->perm[bFR->index];
+ LevelC = dd->perm[bCR->index];
+
+ if ( LevelF <= LevelC )
+ {
+ if ( bFR != bF )
+ {
+ bF0 = Cudd_Not( cuddE(bFR) );
+ bF1 = Cudd_Not( cuddT(bFR) );
+ }
+ else
+ {
+ bF0 = cuddE(bFR);
+ bF1 = cuddT(bFR);
+ }
+ }
+ else
+ {
+ bF0 = bF1 = bF;
+ }
+
+ if ( LevelC <= LevelF )
+ {
+ if ( bCR != bC )
+ {
+ bC0 = Cudd_Not( cuddE(bCR) );
+ bC1 = Cudd_Not( cuddT(bCR) );
+ }
+ else
+ {
+ bC0 = cuddE(bCR);
+ bC1 = cuddT(bCR);
+ }
+ }
+ else
+ {
+ bC0 = bC1 = bC;
+ }
+
+ assert( bC0 == b0 || bC1 == b0 );
+ if ( bC0 == b0 )
+ return Extra_bddNodePointedByCube( dd, bF1, bC1 );
+ return Extra_bddNodePointedByCube( dd, bF0, bC0 );
+}
+
+#if 0
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdNode * dsdTreeGetPrimeFunction( DdManager * dd, Dsd_Node_t * pNode, int fRemap )
+{
+ DdNode * bCof0, * bCof1, * bCube0, * bCube1, * bNewFunc, * bTemp;
+ int i;
+ int fAllBuffs = 1;
+ static int Permute[MAXINPUTS];
+
+ assert( pNode );
+ assert( !Dsd_IsComplement( pNode ) );
+ assert( pNode->Type == DT_PRIME );
+
+ // transform the function of this block to depend on inputs
+ // corresponding to the formal inputs
+
+ // first, substitute those inputs that have some blocks associated with them
+ // second, remap the inputs to the top of the manager (then, it is easy to output them)
+
+ // start the function
+ bNewFunc = pNode->G; Cudd_Ref( bNewFunc );
+ // go over all primary inputs
+ for ( i = 0; i < pNode->nDecs; i++ )
+ if ( pNode->pDecs[i]->Type != DT_BUF ) // remap only if it is not the buffer
+ {
+ bCube0 = Extra_bddFindOneCube( dd, Cudd_Not(pNode->pDecs[i]->G) ); Cudd_Ref( bCube0 );
+ bCof0 = Cudd_Cofactor( dd, bNewFunc, bCube0 ); Cudd_Ref( bCof0 );
+ Cudd_RecursiveDeref( dd, bCube0 );
+
+ bCube1 = Extra_bddFindOneCube( dd, pNode->pDecs[i]->G ); Cudd_Ref( bCube1 );
+ bCof1 = Cudd_Cofactor( dd, bNewFunc, bCube1 ); Cudd_Ref( bCof1 );
+ Cudd_RecursiveDeref( dd, bCube1 );
+
+ Cudd_RecursiveDeref( dd, bNewFunc );
+
+ // use the variable in the i-th level of the manager
+// bNewFunc = Cudd_bddIte( dd, dd->vars[dd->invperm[i]],bCof1,bCof0 ); Cudd_Ref( bNewFunc );
+ // use the first variale in the support of the component
+ bNewFunc = Cudd_bddIte( dd, dd->vars[pNode->pDecs[i]->S->index],bCof1,bCof0 ); Cudd_Ref( bNewFunc );
+ Cudd_RecursiveDeref( dd, bCof0 );
+ Cudd_RecursiveDeref( dd, bCof1 );
+ }
+
+ if ( fRemap )
+ {
+ // remap the function to the top of the manager
+ // remap the function to the first variables of the manager
+ for ( i = 0; i < pNode->nDecs; i++ )
+ // Permute[ pNode->pDecs[i]->S->index ] = dd->invperm[i];
+ Permute[ pNode->pDecs[i]->S->index ] = i;
+
+ bNewFunc = Cudd_bddPermute( dd, bTemp = bNewFunc, Permute ); Cudd_Ref( bNewFunc );
+ Cudd_RecursiveDeref( dd, bTemp );
+ }
+
+ Cudd_Deref( bNewFunc );
+ return bNewFunc;
+}
+
+#endif
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
diff --git a/src/bdd/dsd/dsdMan.c b/src/bdd/dsd/dsdMan.c
new file mode 100644
index 00000000..4529e75a
--- /dev/null
+++ b/src/bdd/dsd/dsdMan.c
@@ -0,0 +1,113 @@
+/**CFile****************************************************************
+
+ FileName [dsdMan.c]
+
+ PackageName [DSD: Disjoint-support decomposition package.]
+
+ Synopsis [APIs of the DSD manager.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 8.0. Started - September 22, 2003.]
+
+ Revision [$Id: dsdMan.c,v 1.0 2002/22/09 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "dsdInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// API OF DSD MANAGER ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Starts the DSD manager.]
+
+ Description [Takes the started BDD manager and the maximum support size
+ of the function to be DSD-decomposed. The manager should have at least as
+ many variables as there are variables in the support. The functions should
+ be expressed using the first nSuppSizeMax variables in the manager (these
+ may be ordered not necessarily on top of the manager).]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Dsd_Manager_t * Dsd_ManagerStart( DdManager * dd, int nSuppMax, int fVerbose )
+{
+ Dsd_Manager_t * dMan;
+ Dsd_Node_t * pNode;
+ int i;
+
+ assert( nSuppMax <= dd->size );
+
+ dMan = ALLOC( Dsd_Manager_t, 1 );
+ memset( dMan, 0, sizeof(Dsd_Manager_t) );
+ dMan->dd = dd;
+ dMan->nInputs = nSuppMax;
+ dMan->fVerbose = fVerbose;
+ dMan->nRoots = 0;
+ dMan->nRootsAlloc = 50;
+ dMan->pRoots = (Dsd_Node_t **) malloc( dMan->nRootsAlloc * sizeof(Dsd_Node_t *) );
+ dMan->pInputs = (Dsd_Node_t **) malloc( dMan->nInputs * sizeof(Dsd_Node_t *) );
+
+ // create the primary inputs and insert them into the table
+ dMan->Table = st_init_table(st_ptrcmp, st_ptrhash);
+ for ( i = 0; i < dMan->nInputs; i++ )
+ {
+ pNode = Dsd_TreeNodeCreate( DSD_NODE_BUF, 1, 0 );
+ pNode->G = dd->vars[i]; Cudd_Ref( pNode->G );
+ pNode->S = dd->vars[i]; Cudd_Ref( pNode->S );
+ st_insert( dMan->Table, (char*)dd->vars[i], (char*)pNode );
+ dMan->pInputs[i] = pNode;
+ }
+ pNode = Dsd_TreeNodeCreate( DSD_NODE_CONST1, 0, 0 );
+ pNode->G = b1; Cudd_Ref( pNode->G );
+ pNode->S = b1; Cudd_Ref( pNode->S );
+ st_insert( dMan->Table, (char*)b1, (char*)pNode );
+
+ Dsd_CheckCacheAllocate( 5000 );
+ return dMan;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Stops the DSD manager.]
+
+ Description [Stopping the DSD manager automatically derefereces and
+ deallocates all the DSD nodes that were created during the life time
+ of the DSD manager. As a result, the user does not need to deref or
+ deallocate any DSD nodes or trees that are derived and placed in
+ the manager while it exists.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Dsd_ManagerStop( Dsd_Manager_t * dMan )
+{
+ st_generator * gen;
+ Dsd_Node_t * pNode;
+ DdNode * bFunc;
+ // delete the nodes
+ st_foreach_item( dMan->Table, gen, (char**)&bFunc, (char**)&pNode )
+ Dsd_TreeNodeDelete( dMan->dd, Dsd_Regular(pNode) );
+ st_free_table(dMan->Table);
+ free( dMan->pInputs );
+ free( dMan->pRoots );
+ free( dMan );
+ Dsd_CheckCacheDeallocate();
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
diff --git a/src/bdd/dsd/dsdProc.c b/src/bdd/dsd/dsdProc.c
new file mode 100644
index 00000000..38cdc2b8
--- /dev/null
+++ b/src/bdd/dsd/dsdProc.c
@@ -0,0 +1,1607 @@
+/**CFile****************************************************************
+
+ FileName [dsdProc.c]
+
+ PackageName [DSD: Disjoint-support decomposition package.]
+
+ Synopsis [The core procedures of the package.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 8.0. Started - September 22, 2003.]
+
+ Revision [$Id: dsdProc.c,v 1.0 2002/22/09 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "dsdInt.h"
+
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// the most important procedures
+void dsdKernelDecompose( Dsd_Manager_t * pDsdMan, DdNode ** pbFuncs, int nFuncs );
+static Dsd_Node_t * dsdKernelDecompose_rec( Dsd_Manager_t * pDsdMan, DdNode * F );
+
+// additional procedures
+static Dsd_Node_t * dsdKernelFindContainingComponent( Dsd_Manager_t * pDsdMan, Dsd_Node_t * pWhere, DdNode * Var, int * fPolarity );
+static int dsdKernelFindCommonComponents( Dsd_Manager_t * pDsdMan, Dsd_Node_t * pL, Dsd_Node_t * pH, Dsd_Node_t *** pCommon, Dsd_Node_t ** pLastDiffL, Dsd_Node_t ** pLastDiffH );
+static void dsdKernelComputeSumOfComponents( Dsd_Manager_t * pDsdMan, Dsd_Node_t ** pCommon, int nCommon, DdNode ** pCompF, DdNode ** pCompS, int fExor );
+static int dsdKernelCheckContainment( Dsd_Manager_t * pDsdMan, Dsd_Node_t * pL, Dsd_Node_t * pH, Dsd_Node_t ** pLarge, Dsd_Node_t ** pSmall );
+
+// list copying
+static void dsdKernelCopyListPlusOne( Dsd_Node_t * p, Dsd_Node_t * First, Dsd_Node_t ** ppList, int nListSize );
+static void dsdKernelCopyListPlusOneMinusOne( Dsd_Node_t * p, Dsd_Node_t * First, Dsd_Node_t ** ppList, int nListSize, int Skipped );
+
+// debugging procedures
+static int dsdKernelVerifyDecomposition( Dsd_Manager_t * pDsdMan, Dsd_Node_t * pDE );
+
+////////////////////////////////////////////////////////////////////////
+/// STATIC VARIABLES ///
+////////////////////////////////////////////////////////////////////////
+
+// the counter of marks
+static int s_Mark;
+
+// debugging flag
+static int s_Show = 0;
+// temporary var used for debugging
+static int Depth = 0;
+
+static int s_Loops1;
+static int s_Loops2;
+static int s_Loops3;
+static int s_Pivot;
+static int s_PivotNo;
+static int s_Common;
+static int s_CommonNo;
+
+static int s_Case4Calls;
+static int s_Case4CallsSpecial;
+
+static int s_Case5;
+static int s_Loops2Useless;
+
+
+static int s_DecNodesTotal;
+static int s_DecNodesUsed;
+
+// statistical variables
+static int s_nDecBlocks;
+static int s_nLiterals;
+static int s_nExorGates;
+static int s_nReusedBlocks;
+static int s_nCascades;
+static float s_nArea;
+static float s_MaxDelay;
+static long s_Time;
+static int s_nInvertors;
+static int s_nPrimeBlocks;
+
+static int HashSuccess = 0;
+static int HashFailure = 0;
+
+static int s_CacheEntries;
+
+
+////////////////////////////////////////////////////////////////////////
+/// DECOMPOSITION FUNCTIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Performs DSD for the array of functions represented by BDDs.]
+
+ Description [This function takes the DSD manager, which should be
+ previously allocated by the call to Dsd_ManagerStart(). The resulting
+ DSD tree is stored in the DSD manager (pDsdMan->pRoots, pDsdMan->nRoots).
+ Access to the tree is through the APIs of the manager. The resulting
+ tree is a shared DSD DAG for the functions given in the array. For one
+ function the resulting DAG is always a tree. The root node pointers can
+ be complemented, as discussed in the literature referred to in "dsd.h".
+ This procedure can be called repeatedly for different functions. There is
+ no need to remove the decomposition tree after it is returned, because
+ the next call to the DSD manager will "recycle" the tree. The user should
+ not modify or dereference any data associated with the nodes of the
+ DSD trees (the user can only change the contents of a temporary
+ mark associated with each node by the calling to Dsd_NodeSetMark()).
+ All the decomposition trees and intermediate nodes will be removed when
+ the DSD manager is deallocated at the end by calling Dsd_ManagerStop().]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Dsd_Decompose( Dsd_Manager_t * pDsdMan, DdNode ** pbFuncs, int nFuncs )
+{
+ DdManager * dd = pDsdMan->dd;
+ int i;
+ long clk;
+ Dsd_Node_t * pTemp;
+ int SumMaxGateSize = 0;
+ int nDecOutputs = 0;
+ int nCBFOutputs = 0;
+/*
+s_Loops1 = 0;
+s_Loops2 = 0;
+s_Loops3 = 0;
+s_Case4Calls = 0;
+s_Case4CallsSpecial = 0;
+s_Case5 = 0;
+s_Loops2Useless = 0;
+*/
+ // resize the number of roots in the manager
+ if ( pDsdMan->nRootsAlloc < nFuncs )
+ {
+ if ( pDsdMan->nRootsAlloc > 0 )
+ free( pDsdMan->pRoots );
+ pDsdMan->nRootsAlloc = nFuncs;
+ pDsdMan->pRoots = (Dsd_Node_t **) malloc( pDsdMan->nRootsAlloc * sizeof(Dsd_Node_t *) );
+ }
+
+ if ( pDsdMan->fVerbose )
+ printf( "\nDecomposability statistics for individual outputs:\n" );
+
+ // set the counter of decomposition nodes
+ s_nDecBlocks = 0;
+
+ // perform decomposition for all outputs
+ clk = clock();
+ pDsdMan->nRoots = 0;
+ s_nCascades = 0;
+ for ( i = 0; i < nFuncs; i++ )
+ {
+ int nLiteralsPrev;
+ int nDecBlocksPrev;
+ int nExorGatesPrev;
+ int nReusedBlocksPres;
+ int nCascades;
+ int MaxBlock;
+ int nPrimeBlocks;
+ long clk;
+
+ clk = clock();
+ nLiteralsPrev = s_nLiterals;
+ nDecBlocksPrev = s_nDecBlocks;
+ nExorGatesPrev = s_nExorGates;
+ nReusedBlocksPres = s_nReusedBlocks;
+ nPrimeBlocks = s_nPrimeBlocks;
+
+ pDsdMan->pRoots[ pDsdMan->nRoots++ ] = dsdKernelDecompose_rec( pDsdMan, pbFuncs[i] );
+
+ Dsd_TreeNodeGetInfoOne( pDsdMan->pRoots[i], &nCascades, &MaxBlock );
+ s_nCascades = ddMax( s_nCascades, nCascades );
+ pTemp = Dsd_Regular(pDsdMan->pRoots[i]);
+ if ( pTemp->Type != DSD_NODE_PRIME || pTemp->nDecs != Extra_bddSuppSize(dd,pTemp->S) )
+ nDecOutputs++;
+ if ( MaxBlock < 3 )
+ nCBFOutputs++;
+ SumMaxGateSize += MaxBlock;
+
+ if ( pDsdMan->fVerbose )
+ {
+ printf("#%02d: ", i );
+ printf("Ins=%2d. ", Cudd_SupportSize(dd,pbFuncs[i]) );
+ printf("Gts=%3d. ", Dsd_TreeCountNonTerminalNodesOne( pDsdMan->pRoots[i] ) );
+ printf("Pri=%3d. ", Dsd_TreeCountPrimeNodesOne( pDsdMan->pRoots[i] ) );
+ printf("Max=%3d. ", MaxBlock );
+ printf("Reuse=%2d. ", s_nReusedBlocks-nReusedBlocksPres );
+ printf("Csc=%2d. ", nCascades );
+ printf("T= %.2f s. ", (float)(clock()-clk)/(float)(CLOCKS_PER_SEC) ) ;
+ printf("Bdd=%2d. ", Cudd_DagSize(pbFuncs[i]) );
+ printf("\n");
+ fflush( stdout );
+ }
+ }
+ assert( pDsdMan->nRoots == nFuncs );
+
+ if ( pDsdMan->fVerbose )
+ {
+ printf( "\n" );
+ printf( "The cumulative decomposability statistics:\n" );
+ printf( " Total outputs = %5d\n", nFuncs );
+ printf( " Decomposable outputs = %5d\n", nDecOutputs );
+ printf( " Completely decomposable outputs = %5d\n", nCBFOutputs );
+ printf( " The sum of max gate sizes = %5d\n", SumMaxGateSize );
+ printf( " Shared BDD size = %5d\n", Cudd_SharingSize( pbFuncs, nFuncs ) );
+ printf( " Decomposition entries = %5d\n", st_count( pDsdMan->Table ) );
+ printf( " Pure decomposition time = %.2f sec\n", (float)(clock() - clk)/(float)(CLOCKS_PER_SEC) );
+ }
+/*
+ printf( "s_Loops1 = %d.\n", s_Loops1 );
+ printf( "s_Loops2 = %d.\n", s_Loops2 );
+ printf( "s_Loops3 = %d.\n", s_Loops3 );
+ printf( "s_Case4Calls = %d.\n", s_Case4Calls );
+ printf( "s_Case4CallsSpecial = %d.\n", s_Case4CallsSpecial );
+ printf( "s_Case5 = %d.\n", s_Case5 );
+ printf( "s_Loops2Useless = %d.\n", s_Loops2Useless );
+*/
+}
+
+/**Function*************************************************************
+
+ Synopsis [The main function of this module. Recursive implementation of DSD.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Dsd_Node_t * dsdKernelDecompose_rec( Dsd_Manager_t * pDsdMan, DdNode * bFunc0 )
+{
+ DdManager * dd = pDsdMan->dd;
+ DdNode * bLow;
+ DdNode * bLowR;
+ DdNode * bHigh;
+
+ int VarInt;
+ DdNode * bVarCur;
+ Dsd_Node_t * pVarCurDE;
+ // works only if var indices start from 0!!!
+ DdNode * bSuppNew = NULL, * bTemp;
+
+ int fContained;
+ int nSuppLH;
+ int nSuppL;
+ int nSuppH;
+
+
+
+ // various decomposition nodes
+ Dsd_Node_t * pThis, * pL, * pH, * pLR, * pHR;
+
+ Dsd_Node_t * pSmallR, * pLargeR;
+ Dsd_Node_t * pTableEntry;
+
+
+ // treat the complemented case
+ DdNode * bF = Cudd_Regular(bFunc0);
+ int fCompF = (int)(bF != bFunc0);
+
+ // check cache
+ if ( st_lookup( pDsdMan->Table, (char*)bF, (char**)&pTableEntry ) )
+ { // the entry is present
+ HashSuccess++;
+ return Dsd_NotCond( pTableEntry, fCompF );
+ }
+ HashFailure++;
+ Depth++;
+
+ // proceed to consider "four cases"
+ //////////////////////////////////////////////////////////////////////
+ // TERMINAL CASES - CASES 1 and 2
+ //////////////////////////////////////////////////////////////////////
+ bLow = cuddE(bF);
+ bLowR = Cudd_Regular(bLow);
+ bHigh = cuddT(bF);
+ VarInt = bF->index;
+ bVarCur = dd->vars[VarInt];
+ pVarCurDE = pDsdMan->pInputs[VarInt];
+ // works only if var indices start from 0!!!
+ bSuppNew = NULL;
+
+ if ( bLowR->index == CUDD_CONST_INDEX || bHigh->index == CUDD_CONST_INDEX )
+ { // one of the cofactors in the constant
+ if ( bHigh == b1 ) // bHigh cannot be equal to b0, because then it will be complemented
+ if ( bLow == b0 ) // bLow cannot be equal to b1, because then the node will have bLow == bHigh
+ /////////////////////////////////////////////////////////////////
+ // bLow == 0, bHigh == 1, F = x'&0 + x&1 = x
+ /////////////////////////////////////////////////////////////////
+ { // create the elementary variable node
+ assert(0); // should be already in the hash table
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_BUF, 1, s_nDecBlocks++ );
+ pThis->pDecs[0] = NULL;
+ }
+ else // if ( bLow != constant )
+ /////////////////////////////////////////////////////////////////
+ // bLow != const, bHigh == 1, F = x'&bLow + x&1 = bLow + x --- DSD_NODE_OR(x,bLow)
+ /////////////////////////////////////////////////////////////////
+ {
+ pL = dsdKernelDecompose_rec( pDsdMan, bLow );
+ pLR = Dsd_Regular( pL );
+ bSuppNew = Cudd_bddAnd( dd, bVarCur, pLR->S ); Cudd_Ref(bSuppNew);
+ if ( pLR->Type == DSD_NODE_OR && pL == pLR ) // OR and no complement
+ { // add to the components
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_OR, pL->nDecs+1, s_nDecBlocks++ );
+ dsdKernelCopyListPlusOne( pThis, pVarCurDE, pL->pDecs, pL->nDecs );
+ }
+ else // all other cases
+ { // create a new 2-input OR-gate
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_OR, 2, s_nDecBlocks++ );
+ dsdKernelCopyListPlusOne( pThis, pVarCurDE, &pL, 1 );
+ }
+ }
+ else // if ( bHigh != const ) // meaning that bLow should be a constant
+ {
+ pH = dsdKernelDecompose_rec( pDsdMan, bHigh );
+ pHR = Dsd_Regular( pH );
+ bSuppNew = Cudd_bddAnd( dd, bVarCur, pHR->S ); Cudd_Ref(bSuppNew);
+ if ( bLow == b0 )
+ /////////////////////////////////////////////////////////////////
+ // Low == 0, High != 1, F = x'&0+x&High = (x'+High')'--- NOR(x',High')
+ /////////////////////////////////////////////////////////////////
+ if ( pHR->Type == DSD_NODE_OR && pH != pHR ) // DSD_NODE_OR and complement
+ { // add to the components
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_OR, pHR->nDecs+1, s_nDecBlocks++ );
+ dsdKernelCopyListPlusOne( pThis, Dsd_Not(pVarCurDE), pHR->pDecs, pHR->nDecs );
+ pThis = Dsd_Not(pThis);
+ }
+ else // all other cases
+ { // create a new 2-input NOR gate
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_OR, 2, s_nDecBlocks++ );
+ pH = Dsd_Not(pH);
+ dsdKernelCopyListPlusOne( pThis, Dsd_Not(pVarCurDE), &pH, 1 );
+ pThis = Dsd_Not(pThis);
+ }
+ else // if ( bLow == b1 )
+ /////////////////////////////////////////////////////////////////
+ // Low == 1, High != 1, F = x'&1 + x&High = x' + High --- DSD_NODE_OR(x',High)
+ /////////////////////////////////////////////////////////////////
+ if ( pHR->Type == DSD_NODE_OR && pH == pHR ) // OR and no complement
+ { // add to the components
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_OR, pH->nDecs+1, s_nDecBlocks++ );
+ dsdKernelCopyListPlusOne( pThis, Dsd_Not(pVarCurDE), pH->pDecs, pH->nDecs );
+ }
+ else // all other cases
+ { // create a new 2-input OR-gate
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_OR, 2, s_nDecBlocks++ );
+ dsdKernelCopyListPlusOne( pThis, Dsd_Not(pVarCurDE), &pH, 1 );
+ }
+ }
+ goto EXIT;
+ }
+ // else if ( bLow != const && bHigh != const )
+
+ // the case of equal cofactors (up to complementation)
+ if ( bLowR == bHigh )
+ /////////////////////////////////////////////////////////////////
+ // Low == G, High == G', F = x'&G + x&G' = (x(+)G) --- EXOR(x,Low)
+ /////////////////////////////////////////////////////////////////
+ {
+ pL = dsdKernelDecompose_rec( pDsdMan, bLow );
+ pLR = Dsd_Regular( pL );
+ bSuppNew = Cudd_bddAnd( dd, bVarCur, pLR->S ); Cudd_Ref(bSuppNew);
+ if ( pLR->Type == DSD_NODE_EXOR ) // complemented or not - does not matter!
+ { // add to the components
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_EXOR, pLR->nDecs+1, s_nDecBlocks++ );
+ dsdKernelCopyListPlusOne( pThis, pVarCurDE, pLR->pDecs, pLR->nDecs );
+ if ( pL != pLR )
+ pThis = Dsd_Not( pThis );
+ }
+ else // all other cases
+ { // create a new 2-input EXOR-gate
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_EXOR, 2, s_nDecBlocks++ );
+ if ( pL != pLR ) // complemented
+ {
+ dsdKernelCopyListPlusOne( pThis, pVarCurDE, &pLR, 1 );
+ pThis = Dsd_Not( pThis );
+ }
+ else // non-complemented
+ dsdKernelCopyListPlusOne( pThis, pVarCurDE, &pL, 1 );
+ }
+ goto EXIT;
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // solve subproblems
+ //////////////////////////////////////////////////////////////////////
+ pL = dsdKernelDecompose_rec( pDsdMan, bLow );
+ pH = dsdKernelDecompose_rec( pDsdMan, bHigh );
+ pLR = Dsd_Regular( pL );
+ pHR = Dsd_Regular( pH );
+
+ assert( pLR->Type == DSD_NODE_BUF || pLR->Type == DSD_NODE_OR || pLR->Type == DSD_NODE_EXOR || pLR->Type == DSD_NODE_PRIME );
+ assert( pHR->Type == DSD_NODE_BUF || pHR->Type == DSD_NODE_OR || pHR->Type == DSD_NODE_EXOR || pHR->Type == DSD_NODE_PRIME );
+
+/*
+if ( Depth == 1 )
+{
+// PRK(bLow,pDecTreeTotal->nInputs);
+// PRK(bHigh,pDecTreeTotal->nInputs);
+if ( s_Show )
+{
+ PRD( pL );
+ PRD( pH );
+}
+}
+*/
+ // compute the new support
+ bTemp = Cudd_bddAnd( dd, pLR->S, pHR->S ); Cudd_Ref( bTemp );
+ nSuppL = Extra_bddSuppSize( dd, pLR->S );
+ nSuppH = Extra_bddSuppSize( dd, pHR->S );
+ nSuppLH = Extra_bddSuppSize( dd, bTemp );
+ bSuppNew = Cudd_bddAnd( dd, bTemp, bVarCur ); Cudd_Ref( bSuppNew );
+ Cudd_RecursiveDeref( dd, bTemp );
+
+
+ // several possibilities are possible
+ // (1) support of one component contains another
+ // (2) none of the supports is contained in another
+ fContained = dsdKernelCheckContainment( pDsdMan, pLR, pHR, &pLargeR, &pSmallR );
+
+ //////////////////////////////////////////////////////////////////////
+ // CASE 3.b One of the cofactors in a constant (OR and EXOR)
+ //////////////////////////////////////////////////////////////////////
+ // the support of the larger component should contain the support of the smaller
+ // it is possible to have PRIME function in this role
+ // for example: F = ITE( a+b, c(+)d, e+f ), F0 = ITE( b, c(+)d, e+f ), F1 = c(+)d
+ if ( fContained )
+ {
+ Dsd_Node_t * pSmall, * pLarge;
+ int c, iCompLarge; // the number of the component is Large is equal to the whole of Small
+ int fLowIsLarge;
+
+ DdNode * bFTemp; // the changed input function
+ Dsd_Node_t * pDETemp, * pDENew;
+
+ Dsd_Node_t * pComp = NULL;
+ int nComp;
+
+ if ( pSmallR == pLR )
+ { // Low is Small => High is Large
+ pSmall = pL;
+ pLarge = pH;
+ fLowIsLarge = 0;
+ }
+ else
+ { // vice versa
+ pSmall = pH;
+ pLarge = pL;
+ fLowIsLarge = 1;
+ }
+
+ // treat the situation when the larger is PRIME
+ if ( pLargeR->Type == DSD_NODE_PRIME ) //&& pLargeR->nDecs != pSmallR->nDecs )
+ {
+ // QUESTION: Is it possible for pLargeR->nDecs > 3
+ // and pSmall contained as one of input in pLarge?
+ // Yes, for example F = a'c + a & MUX(b,c',d) = a'c + abc' + ab'd is non-decomposable
+ // Consider the function H(a->xy) = F( xy, b, c, d )
+ // H0 = H(x=0) = F(0,b,c,d) = c
+ // H1 = F(x=1) = F(y,b,c,d) - non-decomposable
+ //
+ // QUESTION: Is it possible that pLarge is PRIME(3) and pSmall is OR(2),
+ // which is not contained in PRIME as one input?
+ // Yes, for example F = abcd + b'c'd' + a'c'd' = PRIME(ab, c, d)
+ // F(a=0) = c'd' = NOT(OR(a,d)) F(a=1) = bcd + b'c'd' = PRIME(b,c,d)
+ // To find decomposition, we have to prove that F(a=1)|b=0 = F(a=0)
+
+ // Is it possible that (pLargeR->nDecs == pSmallR->nDecs) and yet this case holds?
+ // Yes, consider the function such that F(a=0) = PRIME(a,b+c,d,e) and F(a=1) = OR(b,c,d,e)
+ // They have the same number of inputs and it is possible that they will be the cofactors
+ // as discribed in the previous example.
+
+ // find the component, which when substituted for 0 or 1, produces the desired result
+ int g, fFoundComp; // {0,1} depending on whether setting cofactor to 0 or 1 worked out
+
+ DdNode * bLarge, * bSmall;
+ if ( fLowIsLarge )
+ {
+ bLarge = bLow;
+ bSmall = bHigh;
+ }
+ else
+ {
+ bLarge = bHigh;
+ bSmall = bLow;
+ }
+
+ for ( g = 0; g < pLargeR->nDecs; g++ )
+// if ( g != c )
+ {
+ pDETemp = pLargeR->pDecs[g]; // cannot be complemented
+ if ( Dsd_CheckRootFunctionIdentity( dd, bLarge, bSmall, pDETemp->G, b1 ) )
+ {
+ fFoundComp = 1;
+ break;
+ }
+
+ s_Loops1++;
+
+ if ( Dsd_CheckRootFunctionIdentity( dd, bLarge, bSmall, Cudd_Not(pDETemp->G), b1 ) )
+ {
+ fFoundComp = 0;
+ break;
+ }
+
+ s_Loops1++;
+ }
+
+ if ( g != pLargeR->nDecs )
+ { // decomposition is found
+ if ( fFoundComp )
+ if ( fLowIsLarge )
+ bFTemp = Cudd_bddOr( dd, bVarCur, pLargeR->pDecs[g]->G );
+ else
+ bFTemp = Cudd_bddOr( dd, Cudd_Not(bVarCur), pLargeR->pDecs[g]->G );
+ else
+ if ( fLowIsLarge )
+ bFTemp = Cudd_bddAnd( dd, Cudd_Not(bVarCur), pLargeR->pDecs[g]->G );
+ else
+ bFTemp = Cudd_bddAnd( dd, bVarCur, pLargeR->pDecs[g]->G );
+ Cudd_Ref( bFTemp );
+
+ pDENew = dsdKernelDecompose_rec( pDsdMan, bFTemp );
+ pDENew = Dsd_Regular( pDENew );
+ Cudd_RecursiveDeref( dd, bFTemp );
+
+ // get the new gate
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_PRIME, pLargeR->nDecs, s_nDecBlocks++ );
+ dsdKernelCopyListPlusOneMinusOne( pThis, pDENew, pLargeR->pDecs, pLargeR->nDecs, g );
+ goto EXIT;
+ }
+ }
+
+ // try to find one component in the pLarger that is equal to the whole of pSmaller
+ for ( c = 0; c < pLargeR->nDecs; c++ )
+ if ( pLargeR->pDecs[c] == pSmall || pLargeR->pDecs[c] == Dsd_Not(pSmall) )
+ {
+ iCompLarge = c;
+ break;
+ }
+
+ // assign the equal component
+ if ( c != pLargeR->nDecs ) // the decomposition is possible!
+ {
+ pComp = pLargeR->pDecs[iCompLarge];
+ nComp = 1;
+ }
+ else // the decomposition is still possible
+ { // for example F = OR(ab,c,d), F(a=0) = OR(c,d), F(a=1) = OR(b,c,d)
+ // supp(F0) is contained in supp(F1), Polarity(F(a=0)) == Polarity(F(a=1))
+
+ // try to find a group of common components
+ if ( pLargeR->Type == pSmallR->Type &&
+ (pLargeR->Type == DSD_NODE_EXOR || pSmallR->Type == DSD_NODE_OR&& ((pLarge==pLargeR) == (pSmall==pSmallR))) )
+ {
+ Dsd_Node_t ** pCommon, * pLastDiffL = NULL, * pLastDiffH = NULL;
+ int nCommon = dsdKernelFindCommonComponents( pDsdMan, pLargeR, pSmallR, &pCommon, &pLastDiffL, &pLastDiffH );
+ // if all the components of pSmall are contained in pLarge,
+ // then the decomposition exists
+ if ( nCommon == pSmallR->nDecs )
+ {
+ pComp = pSmallR;
+ nComp = pSmallR->nDecs;
+ }
+ }
+ }
+
+ if ( pComp ) // the decomposition is possible!
+ {
+// Dsd_Node_t * pComp = pLargeR->pDecs[iCompLarge];
+ Dsd_Node_t * pCompR = Dsd_Regular( pComp );
+ int fComp1 = (int)( pLarge != pLargeR );
+ int fComp2 = (int)( pComp != pCompR );
+ int fComp3 = (int)( pSmall != pSmallR );
+
+ DdNode * bFuncComp; // the function of the given component
+ DdNode * bFuncNew; // the function of the input component
+
+ if ( pLargeR->Type == DSD_NODE_OR ) // Figure 4 of Matsunaga's paper
+ {
+ // the decomposition exists only if the polarity assignment
+ // along the paths is the same
+ if ( (fComp1 ^ fComp2) == fComp3 )
+ { // decomposition exists = consider 4 cases
+ // consideration of cases leads to the following conclusion
+ // fComp1 gives the polarity of the resulting DSD_NODE_OR gate
+ // fComp2 gives the polarity of the common component feeding into the DSD_NODE_OR gate
+ //
+ // | fComp1 pL/ |pS
+ // <> .........<=>....... <> |
+ // | / |
+ // [OR] [OR] | fComp3
+ // / \ fComp2 / | \ |
+ // <> <> .......<=>... /..|..<> |
+ // / \ / | \|
+ // [OR] [C] S1 S2 C
+ // / \
+ // <> \
+ // / \
+ // [OR] [x]
+ // / \
+ // S1 S2
+ //
+
+
+ // at this point we have the function F (bFTemp) and the common component C (bFuncComp)
+ // to get the remainder, R, in the relationship F = R + C, supp(R) & supp(C) = 0
+ // we compute the following R = Exist( F - C, supp(C) )
+ bFTemp = (fComp1)? Cudd_Not( bF ): bF;
+ bFuncComp = (fComp2)? Cudd_Not( pCompR->G ): pCompR->G;
+ bFuncNew = Cudd_bddAndAbstract( dd, bFTemp, Cudd_Not(bFuncComp), pCompR->S ); Cudd_Ref( bFuncNew );
+
+ // there is no need to copy the dec entry list first, because pComp is a component
+ // which will not be destroyed by the recursive call to decomposition
+ pDENew = dsdKernelDecompose_rec( pDsdMan, bFuncNew );
+ assert( Dsd_IsComplement(pDENew) ); // follows from the consideration of cases
+ Cudd_RecursiveDeref( dd, bFuncNew );
+
+ // get the new gate
+ if ( nComp == 1 )
+ {
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_OR, 2, s_nDecBlocks++ );
+ pThis->pDecs[0] = pDENew;
+ pThis->pDecs[1] = pComp; // takes the complement
+ }
+ else
+ { // pComp is not complemented
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_OR, nComp+1, s_nDecBlocks++ );
+ dsdKernelCopyListPlusOne( pThis, pDENew, pComp->pDecs, nComp );
+ }
+
+ if ( fComp1 )
+ pThis = Dsd_Not( pThis );
+ goto EXIT;
+ }
+ }
+ else if ( pLargeR->Type == DSD_NODE_EXOR ) // Figure 5 of Matsunaga's paper (with correction)
+ { // decomposition always exists = consider 4 cases
+
+ // consideration of cases leads to the following conclusion
+ // fComp3 gives the COMPLEMENT of the polarity of the resulting EXOR gate
+ // (if fComp3 is 0, the EXOR gate is complemented, and vice versa)
+ //
+ // | fComp1 pL/ |pS
+ // <> .........<=>....... /....| fComp3
+ // | / |
+ // [XOR] [XOR] |
+ // / \ fComp2==0 / | \ |
+ // / \ / | \ |
+ // / \ / | \|
+ // [OR] [C] S1 S2 C
+ // / \
+ // <> \
+ // / \
+ // [XOR] [x]
+ // / \
+ // S1 S2
+ //
+
+ assert( fComp2 == 0 );
+ // find the functionality of the lower gates
+ bFTemp = (fComp3)? bF: Cudd_Not( bF );
+ bFuncNew = Cudd_bddXor( dd, bFTemp, pComp->G ); Cudd_Ref( bFuncNew );
+
+ pDENew = dsdKernelDecompose_rec( pDsdMan, bFuncNew );
+ assert( !Dsd_IsComplement(pDENew) ); // follows from the consideration of cases
+ Cudd_RecursiveDeref( dd, bFuncNew );
+
+ // get the new gate
+ if ( nComp == 1 )
+ {
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_EXOR, 2, s_nDecBlocks++ );
+ pThis->pDecs[0] = pDENew;
+ pThis->pDecs[1] = pComp;
+ }
+ else
+ { // pComp is not complemented
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_EXOR, nComp+1, s_nDecBlocks++ );
+ dsdKernelCopyListPlusOne( pThis, pDENew, pComp->pDecs, nComp );
+ }
+
+ if ( !fComp3 )
+ pThis = Dsd_Not( pThis );
+ goto EXIT;
+ }
+ }
+ }
+
+ // this case was added to fix the trivial bug found November 4, 2002 in Japan
+ // by running the example provided by T. Sasao
+ if ( nSuppLH == nSuppL + nSuppH ) // the supports of the components are disjoint
+ {
+ // create a new component of the type ITE( a, pH, pL )
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_PRIME, 3, s_nDecBlocks++ );
+ if ( dd->perm[pLR->S->index] < dd->perm[pHR->S->index] ) // pLR is higher in the varible order
+ {
+ pThis->pDecs[1] = pLR;
+ pThis->pDecs[2] = pHR;
+ }
+ else // pHR is higher in the varible order
+ {
+ pThis->pDecs[1] = pHR;
+ pThis->pDecs[2] = pLR;
+ }
+ // add the first component
+ pThis->pDecs[0] = pVarCurDE;
+ goto EXIT;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////
+ // CASE 3.a Neither of the cofactors is a constant (OR, EXOR, PRIME)
+ //////////////////////////////////////////////////////////////////////
+ // the component types are identical
+ // and if they are OR, they are either both complemented or both not complemented
+ // and if they are PRIME, their dec numbers should be the same
+ if ( pLR->Type == pHR->Type &&
+ pLR->Type != DSD_NODE_BUF &&
+ (pLR->Type != DSD_NODE_OR || ( pL == pLR && pH == pHR || pL != pLR && pH != pHR ) ) &&
+ (pLR->Type != DSD_NODE_PRIME || pLR->nDecs == pHR->nDecs) )
+ {
+ // array to store common comps in pL and pH
+ Dsd_Node_t ** pCommon, * pLastDiffL = NULL, * pLastDiffH = NULL;
+ int nCommon = dsdKernelFindCommonComponents( pDsdMan, pLR, pHR, &pCommon, &pLastDiffL, &pLastDiffH );
+ if ( nCommon )
+ {
+ if ( pLR->Type == DSD_NODE_OR ) // Figure 2 of Matsunaga's paper
+ { // at this point we have the function F and the group of common components C
+ // to get the remainder, R, in the relationship F = R + C, supp(R) & supp(C) = 0
+ // we compute the following R = Exist( F - C, supp(C) )
+
+ // compute the sum total of the common components and the union of their supports
+ DdNode * bCommF, * bCommS, * bFTemp, * bFuncNew;
+ Dsd_Node_t * pDENew;
+
+ dsdKernelComputeSumOfComponents( pDsdMan, pCommon, nCommon, &bCommF, &bCommS, 0 );
+ Cudd_Ref( bCommF );
+ Cudd_Ref( bCommS );
+ bFTemp = ( pL != pLR )? Cudd_Not(bF): bF;
+
+ bFuncNew = Cudd_bddAndAbstract( dd, bFTemp, Cudd_Not(bCommF), bCommS ); Cudd_Ref( bFuncNew );
+ Cudd_RecursiveDeref( dd, bCommF );
+ Cudd_RecursiveDeref( dd, bCommS );
+
+ // get the new gate
+
+ // copy the components first, then call the decomposition
+ // because decomposition will distroy the list used for copying
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_OR, nCommon + 1, s_nDecBlocks++ );
+ dsdKernelCopyListPlusOne( pThis, NULL, pCommon, nCommon );
+
+ // call the decomposition recursively
+ pDENew = dsdKernelDecompose_rec( pDsdMan, bFuncNew );
+// assert( !Dsd_IsComplement(pDENew) ); // follows from the consideration of cases
+ Cudd_RecursiveDeref( dd, bFuncNew );
+
+ // add the first component
+ pThis->pDecs[0] = pDENew;
+
+ if ( pL != pLR )
+ pThis = Dsd_Not( pThis );
+ goto EXIT;
+ }
+ else
+ if ( pLR->Type == DSD_NODE_EXOR ) // Figure 3 of Matsunaga's paper
+ {
+ // compute the sum total of the common components and the union of their supports
+ DdNode * bCommF, * bFuncNew;
+ Dsd_Node_t * pDENew;
+ int fCompExor;
+
+ dsdKernelComputeSumOfComponents( pDsdMan, pCommon, nCommon, &bCommF, NULL, 1 );
+ Cudd_Ref( bCommF );
+
+ bFuncNew = Cudd_bddXor( dd, bF, bCommF ); Cudd_Ref( bFuncNew );
+ Cudd_RecursiveDeref( dd, bCommF );
+
+ // get the new gate
+
+ // copy the components first, then call the decomposition
+ // because decomposition will distroy the list used for copying
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_EXOR, nCommon + 1, s_nDecBlocks++ );
+ dsdKernelCopyListPlusOne( pThis, NULL, pCommon, nCommon );
+
+ // call the decomposition recursively
+ pDENew = dsdKernelDecompose_rec( pDsdMan, bFuncNew );
+ Cudd_RecursiveDeref( dd, bFuncNew );
+
+ // remember the fact that it was complemented
+ fCompExor = Dsd_IsComplement(pDENew);
+ pDENew = Dsd_Regular(pDENew);
+
+ // add the first component
+ pThis->pDecs[0] = pDENew;
+
+
+ if ( fCompExor )
+ pThis = Dsd_Not( pThis );
+ goto EXIT;
+ }
+ else
+ if ( pLR->Type == DSD_NODE_PRIME && (nCommon == pLR->nDecs-1 || nCommon == pLR->nDecs) )
+ {
+ // for example the function F(a,b,c,d) = ITE(b,c,a(+)d) produces
+ // two cofactors F(a=0) = PRIME(b,c,d) and F(a=1) = PRIME(b,c,d)
+ // with exactly the same list of common components
+
+ Dsd_Node_t * pDENew;
+ DdNode * bFuncNew;
+ int fCompComp = 0; // this flag can be {0,1,2}
+ // if it is 0 there is no identity
+ // if it is 1/2, the cofactored functions are equal in the direct/complemented polarity
+
+ if ( nCommon == pLR->nDecs )
+ { // all the components are the same
+ // find the formal input, in which pLow and pHigh differ (if such input exists)
+ int m;
+ Dsd_Node_t * pTempL, * pTempH;
+
+ s_Common++;
+ for ( m = 0; m < pLR->nDecs; m++ )
+ {
+ pTempL = pLR->pDecs[m]; // cannot be complemented
+ pTempH = pHR->pDecs[m]; // cannot be complemented
+
+ if ( Dsd_CheckRootFunctionIdentity( dd, bLow, bHigh, pTempL->G, Cudd_Not(pTempH->G) ) &&
+ Dsd_CheckRootFunctionIdentity( dd, bLow, bHigh, Cudd_Not(pTempL->G), pTempH->G ) )
+ {
+ pLastDiffL = pTempL;
+ pLastDiffH = pTempH;
+ assert( pLastDiffL == pLastDiffH );
+ fCompComp = 2;
+ break;
+ }
+
+ s_Loops2++;
+ s_Loops2++;
+/*
+ if ( s_Loops2 % 10000 == 0 )
+ {
+ int i;
+ for ( i = 0; i < pLR->nDecs; i++ )
+ printf( " %d(s=%d)", pLR->pDecs[i]->Type,
+ Extra_bddSuppSize(dd, pLR->pDecs[i]->S) );
+ printf( "\n" );
+ }
+*/
+
+ }
+// if ( pLR->nDecs == Extra_bddSuppSize(dd, pLR->S) )
+// s_Loops2Useless += pLR->nDecs * 2;
+
+ if ( fCompComp )
+ { // put the equal components into pCommon, so that they could be copied into the new dec entry
+ nCommon = 0;
+ for ( m = 0; m < pLR->nDecs; m++ )
+ if ( pLR->pDecs[m] != pLastDiffL )
+ pCommon[nCommon++] = pLR->pDecs[m];
+ assert( nCommon = pLR->nDecs-1 );
+ }
+ }
+ else
+ { // the differing components are known - check that they have compatible PRIME function
+
+ s_CommonNo++;
+
+ // find the numbers of different components
+ assert( pLastDiffL );
+ assert( pLastDiffH );
+ // also, they cannot be complemented, because the decomposition type is PRIME
+
+ if ( Dsd_CheckRootFunctionIdentity( dd, bLow, bHigh, Cudd_Not(pLastDiffL->G), Cudd_Not(pLastDiffH->G) ) &&
+ Dsd_CheckRootFunctionIdentity( dd, bLow, bHigh, pLastDiffL->G, pLastDiffH->G ) )
+ fCompComp = 1;
+ else if ( Dsd_CheckRootFunctionIdentity( dd, bLow, bHigh, pLastDiffL->G, Cudd_Not(pLastDiffH->G) ) &&
+ Dsd_CheckRootFunctionIdentity( dd, bLow, bHigh, Cudd_Not(pLastDiffL->G), pLastDiffH->G ) )
+ fCompComp = 2;
+
+ s_Loops3 += 4;
+ }
+
+ if ( fCompComp )
+ {
+ if ( fCompComp == 1 ) // it is true that bLow(G=0) == bHigh(H=0) && bLow(G=1) == bHigh(H=1)
+ bFuncNew = Cudd_bddIte( dd, bVarCur, pLastDiffH->G, pLastDiffL->G );
+ else // it is true that bLow(G=0) == bHigh(H=1) && bLow(G=1) == bHigh(H=0)
+ bFuncNew = Cudd_bddIte( dd, bVarCur, Cudd_Not(pLastDiffH->G), pLastDiffL->G );
+ Cudd_Ref( bFuncNew );
+
+ // get the new gate
+
+ // copy the components first, then call the decomposition
+ // because decomposition will distroy the list used for copying
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_PRIME, pLR->nDecs, s_nDecBlocks++ );
+ dsdKernelCopyListPlusOne( pThis, NULL, pCommon, nCommon );
+
+ // create a new component
+ pDENew = dsdKernelDecompose_rec( pDsdMan, bFuncNew );
+ Cudd_RecursiveDeref( dd, bFuncNew );
+ // the BDD of the argument function in PRIME decomposition, should be regular
+ pDENew = Dsd_Regular(pDENew);
+
+ // add the first component
+ pThis->pDecs[0] = pDENew;
+ goto EXIT;
+ }
+ } // end of PRIME type
+ } // end of existing common components
+ } // end of CASE 3.a
+
+// if ( Depth != 1)
+// {
+
+//CASE4:
+ //////////////////////////////////////////////////////////////////////
+ // CASE 4
+ //////////////////////////////////////////////////////////////////////
+ {
+ // estimate the number of entries in the list
+ int nEntriesMax = pDsdMan->nInputs - dd->perm[VarInt];
+
+ // create the new decomposition entry
+ int nEntries = 0;
+
+ DdNode * SuppL, * SuppH, * SuppL_init, * SuppH_init;
+ Dsd_Node_t *pHigher, *pLower, * pTemp, * pDENew;
+
+
+ int levTopSuppL;
+ int levTopSuppH;
+ int levTop;
+
+ pThis = Dsd_TreeNodeCreate( DSD_NODE_PRIME, nEntriesMax, s_nDecBlocks++ );
+ pThis->pDecs[ nEntries++ ] = pVarCurDE;
+ // other entries will be added to this list one-by-one during analysis
+
+ // count how many times does it happen that the decomposition entries are
+ s_Case4Calls++;
+
+ // consider the simplest case: when the supports are equal
+ // and at least one of the components
+ // is the PRIME without decompositions, or
+ // when both of them are without decomposition
+ if ( (((pLR->Type == DSD_NODE_PRIME && nSuppL == pLR->nDecs) || (pHR->Type == DSD_NODE_PRIME && nSuppH == pHR->nDecs)) && pLR->S == pHR->S) ||
+ ((pLR->Type == DSD_NODE_PRIME && nSuppL == pLR->nDecs) && (pHR->Type == DSD_NODE_PRIME && nSuppH == pHR->nDecs)) )
+ {
+
+ s_Case4CallsSpecial++;
+ // walk through both supports and create the decomposition list composed of simple entries
+ SuppL = pLR->S;
+ SuppH = pHR->S;
+ do
+ {
+ // determine levels
+ levTopSuppL = cuddI(dd,SuppL->index);
+ levTopSuppH = cuddI(dd,SuppH->index);
+
+ // skip the topmost variable in both supports
+ if ( levTopSuppL <= levTopSuppH )
+ {
+ levTop = levTopSuppL;
+ SuppL = cuddT(SuppL);
+ }
+ else
+ levTop = levTopSuppH;
+
+ if ( levTopSuppH <= levTopSuppL )
+ SuppH = cuddT(SuppH);
+
+ // set the new decomposition entry
+ pThis->pDecs[ nEntries++ ] = pDsdMan->pInputs[ dd->invperm[levTop] ];
+ }
+ while ( SuppL != b1 || SuppH != b1 );
+ }
+ else
+ {
+
+ // compare two different decomposition lists
+ SuppL_init = pLR->S;
+ SuppH_init = pHR->S;
+ // start references (because these supports will change)
+ SuppL = pLR->S; Cudd_Ref( SuppL );
+ SuppH = pHR->S; Cudd_Ref( SuppH );
+ while ( SuppL != b1 || SuppH != b1 )
+ {
+ // determine the top level in cofactors and
+ // whether they have the same top level
+ int TopLevL = cuddI(dd,SuppL->index);
+ int TopLevH = cuddI(dd,SuppH->index);
+ int TopLevel = TopLevH;
+ int fEqualLevel = 0;
+
+ DdNode * bVarTop;
+ DdNode * bSuppSubract;
+
+
+ if ( TopLevL < TopLevH )
+ {
+ pHigher = pLR;
+ pLower = pHR;
+ TopLevel = TopLevL;
+ }
+ else if ( TopLevL > TopLevH )
+ {
+ pHigher = pHR;
+ pLower = pLR;
+ }
+ else
+ fEqualLevel = 1;
+ assert( TopLevel != CUDD_CONST_INDEX );
+
+
+ // find the currently top variable in the decomposition lists
+ bVarTop = dd->vars[dd->invperm[TopLevel]];
+
+ if ( !fEqualLevel )
+ {
+ // find the lower support
+ DdNode * bSuppLower = (TopLevL < TopLevH)? SuppH_init: SuppL_init;
+
+ // find the first component in pHigher
+ // whose support does not overlap with supp(Lower)
+ // and remember the previous component
+ int fPolarity;
+ Dsd_Node_t * pPrev = NULL; // the pointer to the component proceeding pCur
+ Dsd_Node_t * pCur = pHigher; // the first component not contained in supp(Lower)
+ while ( Extra_bddSuppOverlapping( dd, pCur->S, bSuppLower ) )
+ { // get the next component
+ pPrev = pCur;
+ pCur = dsdKernelFindContainingComponent( pDsdMan, pCur, bVarTop, &fPolarity );
+ };
+
+ // look for the possibility to subtract more than one component
+ if ( pPrev == NULL || pPrev->Type == DSD_NODE_PRIME )
+ { // if there is no previous component, or if the previous component is PRIME
+ // there is no way to subtract more than one component
+
+ // add the new decomposition entry (it is already regular)
+ pThis->pDecs[ nEntries++ ] = pCur;
+ // assign the support to be subtracted from both components
+ bSuppSubract = pCur->S;
+ }
+ else // all other types
+ {
+ // go through the decomposition list of pPrev and find components
+ // whose support does not overlap with supp(Lower)
+
+ Dsd_Node_t ** pNonOverlap = ALLOC( Dsd_Node_t *, dd->size );
+ int i, nNonOverlap = 0;
+ for ( i = 0; i < pPrev->nDecs; i++ )
+ {
+ pTemp = Dsd_Regular( pPrev->pDecs[i] );
+ if ( !Extra_bddSuppOverlapping( dd, pTemp->S, bSuppLower ) )
+ pNonOverlap[ nNonOverlap++ ] = pPrev->pDecs[i];
+ }
+ assert( nNonOverlap > 0 );
+
+ if ( nNonOverlap == 1 )
+ { // one one component was found, which is the original one
+ assert( Dsd_Regular(pNonOverlap[0]) == pCur);
+ // add the new decomposition entry
+ pThis->pDecs[ nEntries++ ] = pCur;
+ // assign the support to be subtracted from both components
+ bSuppSubract = pCur->S;
+ }
+ else // more than one components was found
+ {
+ // find the OR (EXOR) of the non-overlapping components
+ DdNode * bCommF;
+ dsdKernelComputeSumOfComponents( pDsdMan, pNonOverlap, nNonOverlap, &bCommF, NULL, (int)(pPrev->Type==DSD_NODE_EXOR) );
+ Cudd_Ref( bCommF );
+
+ // create a new gated
+ pDENew = dsdKernelDecompose_rec( pDsdMan, bCommF );
+ Cudd_RecursiveDeref(dd, bCommF);
+ // make it regular... it must be regular already
+ assert( !Dsd_IsComplement(pDENew) );
+
+ // add the new decomposition entry
+ pThis->pDecs[ nEntries++ ] = pDENew;
+ // assign the support to be subtracted from both components
+ bSuppSubract = pDENew->S;
+ }
+ free( pNonOverlap );
+ }
+
+ // subtract its support from the support of upper component
+ if ( TopLevL < TopLevH )
+ {
+ SuppL = Cudd_bddExistAbstract( dd, bTemp = SuppL, bSuppSubract ); Cudd_Ref( SuppL );
+ Cudd_RecursiveDeref(dd, bTemp);
+ }
+ else
+ {
+ SuppH = Cudd_bddExistAbstract( dd, bTemp = SuppH, bSuppSubract ); Cudd_Ref( SuppH );
+ Cudd_RecursiveDeref(dd, bTemp);
+ }
+ } // end of if ( !fEqualLevel )
+ else // if ( fEqualLevel ) -- they have the same top level var
+ {
+ Dsd_Node_t ** pMarkedLeft = ALLOC( Dsd_Node_t *, dd->size ); // the pointers to the marked blocks
+ char * pMarkedPols = ALLOC( char, dd->size ); // polarities of the marked blocks
+ int nMarkedLeft = 0;
+
+ int fPolarity = 0;
+ Dsd_Node_t * pTempL = pLR;
+
+ int fPolarityCurH = 0;
+ Dsd_Node_t * pPrevH = NULL, * pCurH = pHR;
+
+ int fPolarityCurL = 0;
+ Dsd_Node_t * pPrevL = NULL, * pCurL = pLR; // = pMarkedLeft[0];
+ int index = 1;
+
+ // set the new mark
+ s_Mark++;
+
+ // go over the dec list of pL, mark all components that contain the given variable
+ assert( Extra_bddSuppContainVar( dd, pLR->S, bVarTop ) );
+ assert( Extra_bddSuppContainVar( dd, pHR->S, bVarTop ) );
+ do {
+ pTempL->Mark = s_Mark;
+ pMarkedLeft[ nMarkedLeft ] = pTempL;
+ pMarkedPols[ nMarkedLeft ] = fPolarity;
+ nMarkedLeft++;
+ } while ( pTempL = dsdKernelFindContainingComponent( pDsdMan, pTempL, bVarTop, &fPolarity ) );
+
+ // go over the dec list of pH, and find the component that is marked and the previos one
+ // (such component always exists, because they have common variables)
+ while ( pCurH->Mark != s_Mark )
+ {
+ pPrevH = pCurH;
+ pCurH = dsdKernelFindContainingComponent( pDsdMan, pCurH, bVarTop, &fPolarityCurH );
+ assert( pCurH );
+ }
+
+ // go through the first list once again and find
+ // the component proceeding the one marked found in the second list
+ while ( pCurL != pCurH )
+ {
+ pPrevL = pCurL;
+ pCurL = pMarkedLeft[index];
+ fPolarityCurL = pMarkedPols[index];
+ index++;
+ }
+
+ // look for the possibility to subtract more than one component
+ if ( !pPrevL || !pPrevH || pPrevL->Type != pPrevH->Type || pPrevL->Type == DSD_NODE_PRIME || fPolarityCurL != fPolarityCurH )
+ { // there is no way to extract more than one
+ pThis->pDecs[ nEntries++ ] = pCurH;
+ // assign the support to be subtracted from both components
+ bSuppSubract = pCurH->S;
+ }
+ else
+ {
+ // find the equal components in two decomposition lists
+ Dsd_Node_t ** pCommon, * pLastDiffL = NULL, * pLastDiffH = NULL;
+ int nCommon = dsdKernelFindCommonComponents( pDsdMan, pPrevL, pPrevH, &pCommon, &pLastDiffL, &pLastDiffH );
+
+ if ( nCommon == 0 || nCommon == 1 )
+ { // one one component was found, which is the original one
+ // assert( Dsd_Regular(pCommon[0]) == pCurL);
+ // add the new decomposition entry
+ pThis->pDecs[ nEntries++ ] = pCurL;
+ // assign the support to be subtracted from both components
+ bSuppSubract = pCurL->S;
+ }
+ else // more than one components was found
+ {
+ // find the OR (EXOR) of the non-overlapping components
+ DdNode * bCommF;
+ dsdKernelComputeSumOfComponents( pDsdMan, pCommon, nCommon, &bCommF, NULL, (int)(pPrevL->Type==DSD_NODE_EXOR) );
+ Cudd_Ref( bCommF );
+
+ pDENew = dsdKernelDecompose_rec( pDsdMan, bCommF );
+ assert( !Dsd_IsComplement(pDENew) ); // cannot be complemented because of construction
+ Cudd_RecursiveDeref( dd, bCommF );
+
+ // add the new decomposition entry
+ pThis->pDecs[ nEntries++ ] = pDENew;
+
+ // assign the support to be subtracted from both components
+ bSuppSubract = pDENew->S;
+ }
+ }
+
+ SuppL = Cudd_bddExistAbstract( dd, bTemp = SuppL, bSuppSubract ), Cudd_Ref( SuppL );
+ Cudd_RecursiveDeref(dd, bTemp);
+
+ SuppH = Cudd_bddExistAbstract( dd, bTemp = SuppH, bSuppSubract ), Cudd_Ref( SuppH );
+ Cudd_RecursiveDeref(dd, bTemp);
+
+ free( pMarkedLeft );
+ free( pMarkedPols );
+
+ } // end of if ( fEqualLevel )
+
+ } // end of decomposition list comparison
+ Cudd_RecursiveDeref( dd, SuppL );
+ Cudd_RecursiveDeref( dd, SuppH );
+
+ }
+
+ // check that the estimation of the number of entries was okay
+ assert( nEntries <= nEntriesMax );
+
+// if ( nEntries != Extra_bddSuppSize(dd, bSuppNew) )
+// s_Case5++;
+
+ // update the number of entries in the new decomposition list
+ pThis->nDecs = nEntries;
+ }
+//}
+EXIT:
+
+ {
+ // if the component created is complemented, it represents a function without complement
+ // therefore, as it is, without complement, it should recieve the complemented function
+ Dsd_Node_t * pThisR = Dsd_Regular( pThis );
+ assert( pThisR->G == NULL );
+ assert( pThisR->S == NULL );
+
+ if ( pThisR == pThis ) // set regular function
+ pThisR->G = bF;
+ else // set complemented function
+ pThisR->G = Cudd_Not(bF);
+ Cudd_Ref(bF); // reference the function in the component
+
+ assert( bSuppNew );
+ pThisR->S = bSuppNew; // takes the reference from the new support
+ if ( st_insert( pDsdMan->Table, (char*)bF, (char*)pThis ) )
+ {
+ assert( 0 );
+ }
+ s_CacheEntries++;
+
+
+#if 0
+ if ( dsdKernelVerifyDecomposition(dd, pThis) == 0 )
+ {
+ // write the function, for which verification does not work
+ cout << endl << "Internal verification failed!"" );
+
+ // create the variable mask
+ static int s_pVarMask[MAXINPUTS];
+ int nInputCounter = 0;
+
+ Cudd_SupportArray( dd, bF, s_pVarMask );
+ int k;
+ for ( k = 0; k < dd->size; k++ )
+ if ( s_pVarMask[k] )
+ nInputCounter++;
+
+ cout << endl << "The problem function is "" );
+
+ DdNode * zNewFunc = Cudd_zddIsopCover( dd, bF, bF ); Cudd_Ref( zNewFunc );
+ cuddWriteFunctionSop( stdout, dd, zNewFunc, -1, dd->size, "1", s_pVarMask );
+ Cudd_RecursiveDerefZdd( dd, zNewFunc );
+ }
+#endif
+
+ }
+
+ Depth--;
+ return Dsd_NotCond( pThis, fCompF );
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// OTHER FUNCTIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Finds the corresponding decomposition entry.]
+
+ Description [This function returns the non-complemented pointer to the
+ DecEntry of that component which contains the given variable in its
+ support, or NULL if no such component exists]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Dsd_Node_t * dsdKernelFindContainingComponent( Dsd_Manager_t * pDsdMan, Dsd_Node_t * pWhere, DdNode * Var, int * fPolarity )
+
+{
+ Dsd_Node_t * pTemp;
+ int i;
+
+// assert( !Dsd_IsComplement( pWhere ) );
+// assert( Extra_bddSuppContainVar( pDsdMan->dd, pWhere->S, Var ) );
+
+ if ( pWhere->nDecs == 1 )
+ return NULL;
+
+ for( i = 0; i < pWhere->nDecs; i++ )
+ {
+ pTemp = Dsd_Regular( pWhere->pDecs[i] );
+ if ( Extra_bddSuppContainVar( pDsdMan->dd, pTemp->S, Var ) )
+ {
+ *fPolarity = (int)( pTemp != pWhere->pDecs[i] );
+ return pTemp;
+ }
+ }
+ assert( 0 );
+ return NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Find the common decomposition components.]
+
+ Description [This function determines the common components. It counts
+ the number of common components in the decomposition lists of pL and pH
+ and returns their number and the lists of common components. It assumes
+ that pL and pH are regular pointers. It retuns also the pointers to the
+ last different components encountered in pL and pH.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int dsdKernelFindCommonComponents( Dsd_Manager_t * pDsdMan, Dsd_Node_t * pL, Dsd_Node_t * pH, Dsd_Node_t *** pCommon, Dsd_Node_t ** pLastDiffL, Dsd_Node_t ** pLastDiffH )
+{
+ Dsd_Node_t ** Common = ALLOC( Dsd_Node_t *, pDsdMan->dd->size );
+ int nCommon = 0;
+
+ // pointers to the current decomposition entries
+ Dsd_Node_t * pLcur;
+ Dsd_Node_t * pHcur;
+
+ // the pointers to their supports
+ DdNode * bSLcur;
+ DdNode * bSHcur;
+
+ // the top variable in the supports
+ int TopVar;
+
+ // the indices running through the components
+ int iCurL = 0;
+ int iCurH = 0;
+ while ( iCurL < pL->nDecs && iCurH < pH->nDecs )
+ { // both did not run out
+
+ pLcur = Dsd_Regular(pL->pDecs[iCurL]);
+ pHcur = Dsd_Regular(pH->pDecs[iCurH]);
+
+ bSLcur = pLcur->S;
+ bSHcur = pHcur->S;
+
+ // find out what component is higher in the BDD
+ if ( pDsdMan->dd->perm[bSLcur->index] < pDsdMan->dd->perm[bSHcur->index] )
+ TopVar = bSLcur->index;
+ else
+ TopVar = bSHcur->index;
+
+ if ( TopVar == bSLcur->index && TopVar == bSHcur->index )
+ {
+ // the components may be equal - should match exactly!
+ if ( pL->pDecs[iCurL] == pH->pDecs[iCurH] )
+ Common[nCommon++] = pL->pDecs[iCurL];
+ else
+ {
+ *pLastDiffL = pL->pDecs[iCurL];
+ *pLastDiffH = pH->pDecs[iCurH];
+ }
+
+ // skip both
+ iCurL++;
+ iCurH++;
+ }
+ else if ( TopVar == bSLcur->index )
+ { // the components cannot be equal
+ // skip the top-most one
+ *pLastDiffL = pL->pDecs[iCurL++];
+ }
+ else // if ( TopVar == bSHcur->index )
+ { // the components cannot be equal
+ // skip the top-most one
+ *pLastDiffH = pH->pDecs[iCurH++];
+ }
+ }
+
+ // if one of the lists still has components, write the first one down
+ if ( iCurL < pL->nDecs )
+ *pLastDiffL = pL->pDecs[iCurL];
+
+ if ( iCurH < pH->nDecs )
+ *pLastDiffH = pH->pDecs[iCurH];
+
+ // return the pointer to the array
+ *pCommon = Common;
+ // return the number of common components
+ free( Common );
+ return nCommon;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the sum (OR or EXOR) of the functions of the components.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void dsdKernelComputeSumOfComponents( Dsd_Manager_t * pDsdMan, Dsd_Node_t ** pCommon, int nCommon, DdNode ** pCompF, DdNode ** pCompS, int fExor )
+{
+ DdManager * dd = pDsdMan->dd;
+ DdNode * bF, * bS, * bFadd, * bTemp;
+ Dsd_Node_t * pDE, * pDER;
+ int i;
+
+ // start the function
+ bF = b0; Cudd_Ref( bF );
+ // start the support
+ if ( pCompS )
+ bS = b1, Cudd_Ref( bS );
+
+ assert( nCommon > 0 );
+ for ( i = 0; i < nCommon; i++ )
+ {
+ pDE = pCommon[i];
+ pDER = Dsd_Regular( pDE );
+ bFadd = (pDE != pDER)? Cudd_Not(pDER->G): pDER->G;
+ // add to the function
+ if ( fExor )
+ bF = Cudd_bddXor( dd, bTemp = bF, bFadd );
+ else
+ bF = Cudd_bddOr( dd, bTemp = bF, bFadd );
+ Cudd_Ref( bF );
+ Cudd_RecursiveDeref( dd, bTemp );
+ if ( pCompS )
+ {
+ // add to the support
+ bS = Cudd_bddAnd( dd, bTemp = bS, pDER->S ); Cudd_Ref( bS );
+ Cudd_RecursiveDeref( dd, bTemp );
+ }
+ }
+ // return the function
+ Cudd_Deref( bF );
+ *pCompF = bF;
+
+ // return the support
+ if ( pCompS )
+ Cudd_Deref( bS ), *pCompS = bS;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks support containment of the decomposition components.]
+
+ Description [This function returns 1 if support of one component is contained
+ in that of another. In this case, pLarge (pSmall) is assigned to point to the
+ larger (smaller) support. If the supports are identical return 0, and does not
+ assign the components.]
+]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int dsdKernelCheckContainment( Dsd_Manager_t * pDsdMan, Dsd_Node_t * pL, Dsd_Node_t * pH, Dsd_Node_t ** pLarge, Dsd_Node_t ** pSmall )
+{
+ DdManager * dd = pDsdMan->dd;
+ DdNode * bSuppLarge, * bSuppSmall;
+ int RetValue;
+
+ RetValue = Extra_bddSuppCheckContainment( dd, pL->S, pH->S, &bSuppLarge, &bSuppSmall );
+
+ if ( RetValue == 0 )
+ return 0;
+
+ if ( pH->S == bSuppLarge )
+ {
+ *pLarge = pH;
+ *pSmall = pL;
+ }
+ else // if ( pL->S == bSuppLarge )
+ {
+ *pLarge = pL;
+ *pSmall = pH;
+ }
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Copies the list of components plus one.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void dsdKernelCopyListPlusOne( Dsd_Node_t * p, Dsd_Node_t * First, Dsd_Node_t ** ppList, int nListSize )
+{
+ int i;
+ assert( nListSize+1 == p->nDecs );
+ p->pDecs[0] = First;
+ for( i = 0; i < nListSize; i++ )
+ p->pDecs[i+1] = ppList[i];
+}
+
+/**Function*************************************************************
+
+ Synopsis [Copies the list of components plus one, and skips one.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void dsdKernelCopyListPlusOneMinusOne( Dsd_Node_t * p, Dsd_Node_t * First, Dsd_Node_t ** ppList, int nListSize, int iSkipped )
+{
+ int i, Counter;
+ assert( nListSize == p->nDecs );
+ p->pDecs[0] = First;
+ for( i = 0, Counter = 1; i < nListSize; i++ )
+ if ( i != iSkipped )
+ p->pDecs[Counter++] = ppList[i];
+}
+
+/**Function*************************************************************
+
+ Synopsis [Debugging procedure to compute the functionality of the decomposed structure.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int dsdKernelVerifyDecomposition( Dsd_Manager_t * pDsdMan, Dsd_Node_t * pDE )
+{
+ DdManager * dd = pDsdMan->dd;
+ Dsd_Node_t * pR = Dsd_Regular(pDE);
+ int fCompP = (int)( pDE != pR );
+ int RetValue;
+
+ DdNode * bRes;
+ if ( pR->Type == DSD_NODE_CONST1 )
+ bRes = b1;
+ else if ( pR->Type == DSD_NODE_BUF )
+ bRes = pR->G;
+ else if ( pR->Type == DSD_NODE_OR || pR->Type == DSD_NODE_EXOR )
+ dsdKernelComputeSumOfComponents( pDsdMan, pR->pDecs, pR->nDecs, &bRes, NULL, (int)(pR->Type == DSD_NODE_EXOR) );
+ else if ( pR->Type == DSD_NODE_PRIME )
+ {
+ int i;
+ DdNode ** bGVars = ALLOC( DdNode *, dd->size );
+ // transform the function of this block, so that it depended on inputs
+ // corresponding to the formal inputs
+ DdNode * bNewFunc = Dsd_TreeGetPrimeFunctionOld( dd, pR, 1 ); Cudd_Ref( bNewFunc );
+
+ // compose this function with the inputs
+ // create the elementary permutation
+ for ( i = 0; i < dd->size; i++ )
+ bGVars[i] = dd->vars[i];
+
+ // assign functions to be composed
+ for ( i = 0; i < pR->nDecs; i++ )
+ bGVars[dd->invperm[i]] = pR->pDecs[i]->G;
+
+ // perform the composition
+ bRes = Cudd_bddVectorCompose( dd, bNewFunc, bGVars ); Cudd_Ref( bRes );
+ Cudd_RecursiveDeref( dd, bNewFunc );
+
+ /////////////////////////////////////////////////////////
+ RetValue = (int)( bRes == pR->G );//|| bRes == Cudd_Not(pR->G) );
+ /////////////////////////////////////////////////////////
+ Cudd_Deref( bRes );
+ free( bGVars );
+ }
+ else
+ {
+ assert(0);
+ }
+
+ Cudd_Ref( bRes );
+ RetValue = (int)( bRes == pR->G );//|| bRes == Cudd_Not(pR->G) );
+ Cudd_RecursiveDeref( dd, bRes );
+ return RetValue;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
diff --git a/src/bdd/dsd/dsdTree.c b/src/bdd/dsd/dsdTree.c
new file mode 100644
index 00000000..b1532715
--- /dev/null
+++ b/src/bdd/dsd/dsdTree.c
@@ -0,0 +1,838 @@
+/**CFile****************************************************************
+
+ FileName [dsdTree.c]
+
+ PackageName [DSD: Disjoint-support decomposition package.]
+
+ Synopsis [Managing the decomposition tree.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 8.0. Started - September 22, 2003.]
+
+ Revision [$Id: dsdTree.c,v 1.0 2002/22/09 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "dsdInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static void Dsd_TreeUnmark_rec( Dsd_Node_t * pNode );
+static void Dsd_TreeGetInfo_rec( Dsd_Node_t * pNode, int RankCur );
+static int Dsd_TreeCountNonTerminalNodes_rec( Dsd_Node_t * pNode );
+static int Dsd_TreeCountPrimeNodes_rec( Dsd_Node_t * pNode );
+static int Dsd_TreeCollectDecomposableVars_rec( DdManager * dd, Dsd_Node_t * pNode, int * pVars, int * nVars );
+static void Dsd_TreeCollectNodesDfs_rec( Dsd_Node_t * pNode, Dsd_Node_t * ppNodes[], int * pnNodes );
+static void Dsd_TreePrint_rec( FILE * pFile, Dsd_Node_t * pNode, int fCcmp, char * pInputNames[], char * pOutputName, int nOffset, int * pSigCounter, int fShortNames );
+
+
+////////////////////////////////////////////////////////////////////////
+/// STATIC VARIABLES ///
+////////////////////////////////////////////////////////////////////////
+
+static int s_DepthMax;
+static int s_GateSizeMax;
+
+static int s_CounterBlocks;
+static int s_CounterPos;
+static int s_CounterNeg;
+static int s_CounterNo;
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Create the DSD node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Dsd_Node_t * Dsd_TreeNodeCreate( int Type, int nDecs, int BlockNum )
+{
+ // allocate memory for this node
+ Dsd_Node_t * p = (Dsd_Node_t *) malloc( sizeof(Dsd_Node_t) );
+ memset( p, 0, sizeof(Dsd_Node_t) );
+ p->Type = Type; // the type of this block
+ p->nDecs = nDecs; // the number of decompositions
+ if ( p->nDecs )
+ {
+ p->pDecs = (Dsd_Node_t **) malloc( p->nDecs * sizeof(Dsd_Node_t *) );
+ p->pDecs[0] = NULL;
+ }
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Frees the DSD node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Dsd_TreeNodeDelete( DdManager * dd, Dsd_Node_t * pNode )
+{
+ if ( pNode->G ) Cudd_RecursiveDeref( dd, pNode->G );
+ if ( pNode->S ) Cudd_RecursiveDeref( dd, pNode->S );
+ FREE( pNode->pDecs );
+ FREE( pNode );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Unmarks the decomposition tree.]
+
+ Description [This function assumes that originally pNode->nVisits are
+ set to zero!]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Dsd_TreeUnmark( Dsd_Manager_t * pDsdMan )
+{
+ int i;
+ for ( i = 0; i < pDsdMan->nRoots; i++ )
+ Dsd_TreeUnmark_rec( Dsd_Regular( pDsdMan->pRoots[i] ) );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Recursive unmarking.]
+
+ Description [This function should be called with a non-complemented
+ pointer.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Dsd_TreeUnmark_rec( Dsd_Node_t * pNode )
+{
+ int i;
+
+ assert( pNode );
+ assert( !Dsd_IsComplement( pNode ) );
+ assert( pNode->nVisits > 0 );
+
+ if ( --pNode->nVisits ) // if this is not the last visit, return
+ return;
+
+ // upon the last visit, go through the list of successors and call recursively
+ if ( pNode->Type != DSD_NODE_BUF && pNode->Type != DSD_NODE_CONST1 )
+ for ( i = 0; i < pNode->nDecs; i++ )
+ Dsd_TreeUnmark_rec( Dsd_Regular(pNode->pDecs[i]) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Getting information about the node.]
+
+ Description [This function computes the max depth and the max gate size
+ of the tree rooted at the node.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Dsd_TreeNodeGetInfo( Dsd_Manager_t * pDsdMan, int * DepthMax, int * GateSizeMax )
+{
+ int i;
+ s_DepthMax = 0;
+ s_GateSizeMax = 0;
+
+ for ( i = 0; i < pDsdMan->nRoots; i++ )
+ Dsd_TreeGetInfo_rec( Dsd_Regular( pDsdMan->pRoots[i] ), 0 );
+
+ if ( DepthMax )
+ *DepthMax = s_DepthMax;
+ if ( GateSizeMax )
+ *GateSizeMax = s_GateSizeMax;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Getting information about the node.]
+
+ Description [This function computes the max depth and the max gate size
+ of the tree rooted at the node.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Dsd_TreeNodeGetInfoOne( Dsd_Node_t * pNode, int * DepthMax, int * GateSizeMax )
+{
+ s_DepthMax = 0;
+ s_GateSizeMax = 0;
+
+ Dsd_TreeGetInfo_rec( Dsd_Regular(pNode), 0 );
+
+ if ( DepthMax )
+ *DepthMax = s_DepthMax;
+ if ( GateSizeMax )
+ *GateSizeMax = s_GateSizeMax;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Performs the recursive step of Dsd_TreeNodeGetInfo().]
+
+ Description [pNode is the node, for the tree rooted in which we are
+ determining info. RankCur is the current rank to assign to the node.
+ fSetRank is the flag saying whether the rank will be written in the
+ node. s_DepthMax is the maximum depths of the tree. s_GateSizeMax is
+ the maximum gate size.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Dsd_TreeGetInfo_rec( Dsd_Node_t * pNode, int RankCur )
+{
+ int i;
+ int GateSize;
+
+ assert( pNode );
+ assert( !Dsd_IsComplement( pNode ) );
+ assert( pNode->nVisits >= 0 );
+
+ // we don't want the two-input gates to count for non-decomposable blocks
+ if ( pNode->Type == DSD_NODE_OR ||
+ pNode->Type == DSD_NODE_EXOR )
+ GateSize = 2;
+ else
+ GateSize = pNode->nDecs;
+
+ // update the max size of the node
+ if ( s_GateSizeMax < GateSize )
+ s_GateSizeMax = GateSize;
+
+ if ( pNode->nDecs < 2 )
+ return;
+
+ // update the max rank
+ if ( s_DepthMax < RankCur+1 )
+ s_DepthMax = RankCur+1;
+
+ // call recursively
+ for ( i = 0; i < pNode->nDecs; i++ )
+ Dsd_TreeGetInfo_rec( Dsd_Regular(pNode->pDecs[i]), RankCur+1 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Counts non-terminal nodes of the DSD tree.]
+
+ Description [Nonterminal nodes include all the nodes with the
+ support more than 1. These are OR, EXOR, and PRIME nodes. They
+ do not include the elementary variable nodes and the constant 1
+ node.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Dsd_TreeCountNonTerminalNodes( Dsd_Manager_t * pDsdMan )
+{
+ int Counter, i;
+ Counter = 0;
+ for ( i = 0; i < pDsdMan->nRoots; i++ )
+ Counter += Dsd_TreeCountNonTerminalNodes_rec( Dsd_Regular( pDsdMan->pRoots[i] ) );
+ Dsd_TreeUnmark( pDsdMan );
+ return Counter;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Dsd_TreeCountNonTerminalNodesOne( Dsd_Node_t * pRoot )
+{
+ int Counter = 0;
+
+ // go through the list of successors and call recursively
+ Counter = Dsd_TreeCountNonTerminalNodes_rec( Dsd_Regular(pRoot) );
+
+ Dsd_TreeUnmark_rec( Dsd_Regular(pRoot) );
+ return Counter;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Counts non-terminal nodes for one root.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Dsd_TreeCountNonTerminalNodes_rec( Dsd_Node_t * pNode )
+{
+ int i;
+ int Counter = 0;
+
+ assert( pNode );
+ assert( !Dsd_IsComplement( pNode ) );
+ assert( pNode->nVisits >= 0 );
+
+ if ( pNode->nVisits++ ) // if this is not the first visit, return zero
+ return 0;
+
+ if ( pNode->nDecs <= 1 )
+ return 0;
+
+ // upon the first visit, go through the list of successors and call recursively
+ for ( i = 0; i < pNode->nDecs; i++ )
+ Counter += Dsd_TreeCountNonTerminalNodes_rec( Dsd_Regular(pNode->pDecs[i]) );
+
+ return Counter + 1;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Counts prime nodes of the DSD tree.]
+
+ Description [Prime nodes are nodes with the support more than 2,
+ that is not an OR or EXOR gate.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Dsd_TreeCountPrimeNodes( Dsd_Manager_t * pDsdMan )
+{
+ int Counter, i;
+ Counter = 0;
+ for ( i = 0; i < pDsdMan->nRoots; i++ )
+ Counter += Dsd_TreeCountPrimeNodes_rec( Dsd_Regular( pDsdMan->pRoots[i] ) );
+ Dsd_TreeUnmark( pDsdMan );
+ return Counter;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Counts prime nodes for one root.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Dsd_TreeCountPrimeNodesOne( Dsd_Node_t * pRoot )
+{
+ int Counter = 0;
+
+ // go through the list of successors and call recursively
+ Counter = Dsd_TreeCountPrimeNodes_rec( Dsd_Regular(pRoot) );
+
+ Dsd_TreeUnmark_rec( Dsd_Regular(pRoot) );
+ return Counter;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Dsd_TreeCountPrimeNodes_rec( Dsd_Node_t * pNode )
+{
+ int i;
+ int Counter = 0;
+
+ assert( pNode );
+ assert( !Dsd_IsComplement( pNode ) );
+ assert( pNode->nVisits >= 0 );
+
+ if ( pNode->nVisits++ ) // if this is not the first visit, return zero
+ return 0;
+
+ if ( pNode->nDecs <= 1 )
+ return 0;
+
+ // upon the first visit, go through the list of successors and call recursively
+ for ( i = 0; i < pNode->nDecs; i++ )
+ Counter += Dsd_TreeCountPrimeNodes_rec( Dsd_Regular(pNode->pDecs[i]) );
+
+ if ( pNode->Type == DSD_NODE_PRIME )
+ Counter++;
+
+ return Counter;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Collects the decomposable vars on the PI side.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Dsd_TreeCollectDecomposableVars( Dsd_Manager_t * pDsdMan, int * pVars )
+{
+ int nVars;
+
+ // set the vars collected to 0
+ nVars = 0;
+ Dsd_TreeCollectDecomposableVars_rec( pDsdMan->dd, Dsd_Regular(pDsdMan->pRoots[0]), pVars, &nVars );
+ // return the number of collected vars
+ return nVars;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Implements the recursive part of Dsd_TreeCollectDecomposableVars().]
+
+ Description [Adds decomposable variables as they are found to pVars and increments
+ nVars. Returns 1 if a non-dec node with more than 4 inputs was encountered
+ in the processed subtree. Returns 0, otherwise. ]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Dsd_TreeCollectDecomposableVars_rec( DdManager * dd, Dsd_Node_t * pNode, int * pVars, int * nVars )
+{
+ int fSkipThisNode, i;
+ Dsd_Node_t * pTemp;
+ int fVerbose = 0;
+
+ assert( pNode );
+ assert( !Dsd_IsComplement( pNode ) );
+
+ if ( pNode->nDecs <= 1 )
+ return 0;
+
+ // go through the list of successors and call recursively
+ fSkipThisNode = 0;
+ for ( i = 0; i < pNode->nDecs; i++ )
+ if ( Dsd_TreeCollectDecomposableVars_rec(dd, Dsd_Regular(pNode->pDecs[i]), pVars, nVars) )
+ fSkipThisNode = 1;
+
+ if ( !fSkipThisNode && (pNode->Type == DSD_NODE_OR || pNode->Type == DSD_NODE_EXOR || pNode->nDecs <= 4) )
+ {
+if ( fVerbose )
+printf( "Node of type <%d> (OR=6,EXOR=8,RAND=1): ", pNode->Type );
+
+ for ( i = 0; i < pNode->nDecs; i++ )
+ {
+ pTemp = Dsd_Regular(pNode->pDecs[i]);
+ if ( pTemp->Type == DSD_NODE_BUF )
+ {
+ if ( pVars )
+ pVars[ (*nVars)++ ] = pTemp->S->index;
+ else
+ (*nVars)++;
+
+if ( fVerbose )
+printf( "%d ", pTemp->S->index );
+ }
+ }
+if ( fVerbose )
+printf( "\n" );
+ }
+ else
+ fSkipThisNode = 1;
+
+
+ return fSkipThisNode;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Creates the DFS ordered array of DSD nodes in the tree.]
+
+ Description [The collected nodes do not include the terminal nodes
+ and the constant 1 node. The array of nodes is returned. The number
+ of entries in the array is returned in the variale pnNodes.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Dsd_Node_t ** Dsd_TreeCollectNodesDfs( Dsd_Manager_t * pDsdMan, int * pnNodes )
+{
+ Dsd_Node_t ** ppNodes;
+ int nNodes, nNodesAlloc;
+ int i;
+
+ nNodesAlloc = Dsd_TreeCountNonTerminalNodes(pDsdMan);
+ nNodes = 0;
+ ppNodes = ALLOC( Dsd_Node_t *, nNodesAlloc );
+ for ( i = 0; i < pDsdMan->nRoots; i++ )
+ Dsd_TreeCollectNodesDfs_rec( Dsd_Regular(pDsdMan->pRoots[i]), ppNodes, &nNodes );
+ Dsd_TreeUnmark( pDsdMan );
+ assert( nNodesAlloc == nNodes );
+ *pnNodes = nNodes;
+ return ppNodes;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Dsd_TreeCollectNodesDfs_rec( Dsd_Node_t * pNode, Dsd_Node_t * ppNodes[], int * pnNodes )
+{
+ int i;
+ assert( pNode );
+ assert( !Dsd_IsComplement(pNode) );
+ assert( pNode->nVisits >= 0 );
+
+ if ( pNode->nVisits++ ) // if this is not the first visit, return zero
+ return;
+ if ( pNode->nDecs <= 1 )
+ return;
+
+ // upon the first visit, go through the list of successors and call recursively
+ for ( i = 0; i < pNode->nDecs; i++ )
+ Dsd_TreeCollectNodesDfs_rec( Dsd_Regular(pNode->pDecs[i]), ppNodes, pnNodes );
+
+ ppNodes[ (*pnNodes)++ ] = pNode;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints the decompostion tree into file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Dsd_TreePrint( FILE * pFile, Dsd_Manager_t * pDsdMan, char * pInputNames[], char * pOutputNames[], int fShortNames, int Output )
+{
+ Dsd_Node_t * pNode;
+ int SigCounter;
+ int i;
+ SigCounter = 1;
+
+ if ( Output == -1 )
+ {
+ for ( i = 0; i < pDsdMan->nRoots; i++ )
+ {
+ pNode = Dsd_Regular( pDsdMan->pRoots[i] );
+ Dsd_TreePrint_rec( pFile, pNode, (pNode != pDsdMan->pRoots[i]), pInputNames, pOutputNames[i], 0, &SigCounter, fShortNames );
+ }
+ }
+ else
+ {
+ assert( Output >= 0 && Output < pDsdMan->nRoots );
+ pNode = Dsd_Regular( pDsdMan->pRoots[Output] );
+ Dsd_TreePrint_rec( pFile, pNode, (pNode != pDsdMan->pRoots[Output]), pInputNames, pOutputNames[Output], 0, &SigCounter, fShortNames );
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints the decompostion tree into file.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Dsd_TreePrint_rec( FILE * pFile, Dsd_Node_t * pNode, int fComp, char * pInputNames[], char * pOutputName, int nOffset, int * pSigCounter, int fShortNames )
+{
+ char Buffer[100];
+ Dsd_Node_t * pInput;
+ int * pInputNums;
+ int fCompNew, i;
+
+ assert( pNode->Type == DSD_NODE_BUF || pNode->Type == DSD_NODE_CONST1 ||
+ pNode->Type == DSD_NODE_PRIME || pNode->Type == DSD_NODE_OR || pNode->Type == DSD_NODE_EXOR );
+
+ Extra_PrintSymbols( pFile, ' ', nOffset, 0 );
+ fprintf( pFile, "%s: ", pOutputName );
+ pInputNums = ALLOC( int, pNode->nDecs );
+ if ( pNode->Type == DSD_NODE_CONST1 )
+ {
+ if ( fComp )
+ fprintf( pFile, " Constant 0.\n" );
+ else
+ fprintf( pFile, " Constant 1.\n" );
+ }
+ else if ( pNode->Type == DSD_NODE_BUF )
+ {
+ if ( fComp )
+ fprintf( pFile, " NOT(" );
+ else
+ fprintf( pFile, " " );
+ if ( fShortNames )
+ fprintf( pFile, "%d", pNode->S->index );
+ else
+ fprintf( pFile, "%s", pInputNames[pNode->S->index] );
+ if ( fComp )
+ fprintf( pFile, ")" );
+ fprintf( pFile, "\n" );
+ }
+ else if ( pNode->Type == DSD_NODE_PRIME )
+ {
+ // print the line
+ fprintf( pFile, "PRIME(" );
+ for ( i = 0; i < pNode->nDecs; i++ )
+ {
+ pInput = Dsd_Regular( pNode->pDecs[i] );
+ fCompNew = (int)( pInput != pNode->pDecs[i] );
+ if ( i )
+ fprintf( pFile, "," );
+ if ( pInput->Type == DSD_NODE_BUF )
+ {
+ pInputNums[i] = 0;
+ if ( fCompNew )
+ fprintf( pFile, " NOT(" );
+ else
+ fprintf( pFile, " " );
+ if ( fShortNames )
+ fprintf( pFile, "%d", pInput->S->index );
+ else
+ fprintf( pFile, "%s", pInputNames[pInput->S->index] );
+ if ( fCompNew )
+ fprintf( pFile, ")" );
+ }
+ else
+ {
+ pInputNums[i] = (*pSigCounter)++;
+ fprintf( pFile, " <%d>", pInputNums[i] );
+ }
+ }
+ fprintf( pFile, " )\n" );
+ // call recursively for the following blocks
+ for ( i = 0; i < pNode->nDecs; i++ )
+ if ( pInputNums[i] )
+ {
+ pInput = Dsd_Regular( pNode->pDecs[i] );
+ fCompNew = (int)( pInput != pNode->pDecs[i] );
+ sprintf( Buffer, "<%d>", pInputNums[i] );
+ Dsd_TreePrint_rec( pFile, Dsd_Regular( pNode->pDecs[i] ), fCompNew, pInputNames, Buffer, nOffset + 6, pSigCounter, fShortNames );
+ }
+ }
+ else if ( pNode->Type == DSD_NODE_OR )
+ {
+ // print the line
+ if ( fComp )
+ fprintf( pFile, "AND(" );
+ else
+ fprintf( pFile, "OR(" );
+ for ( i = 0; i < pNode->nDecs; i++ )
+ {
+ pInput = Dsd_Regular( pNode->pDecs[i] );
+ fCompNew = (int)( pInput != pNode->pDecs[i] );
+ if ( i )
+ fprintf( pFile, "," );
+ if ( pInput->Type == DSD_NODE_BUF )
+ {
+ pInputNums[i] = 0;
+ if ( fCompNew )
+ fprintf( pFile, " NOT(" );
+ else
+ fprintf( pFile, " " );
+ if ( fShortNames )
+ fprintf( pFile, "%d", pInput->S->index );
+ else
+ fprintf( pFile, "%s", pInputNames[pInput->S->index] );
+ if ( fCompNew )
+ fprintf( pFile, ")" );
+ }
+ else
+ {
+ pInputNums[i] = (*pSigCounter)++;
+ fprintf( pFile, " <%d>", pInputNums[i] );
+ }
+ }
+ fprintf( pFile, " )\n" );
+ // call recursively for the following blocks
+ for ( i = 0; i < pNode->nDecs; i++ )
+ if ( pInputNums[i] )
+ {
+ pInput = Dsd_Regular( pNode->pDecs[i] );
+ fCompNew = (int)( pInput != pNode->pDecs[i] );
+ sprintf( Buffer, "<%d>", pInputNums[i] );
+ Dsd_TreePrint_rec( pFile, Dsd_Regular( pNode->pDecs[i] ), fComp ^ fCompNew, pInputNames, Buffer, nOffset + 6, pSigCounter, fShortNames );
+ }
+ }
+ else if ( pNode->Type == DSD_NODE_EXOR )
+ {
+ // print the line
+ if ( fComp )
+ fprintf( pFile, "NEXOR(" );
+ else
+ fprintf( pFile, "EXOR(" );
+ for ( i = 0; i < pNode->nDecs; i++ )
+ {
+ pInput = Dsd_Regular( pNode->pDecs[i] );
+ fCompNew = (int)( pInput != pNode->pDecs[i] );
+ if ( i )
+ fprintf( pFile, "," );
+ if ( pInput->Type == DSD_NODE_BUF )
+ {
+ pInputNums[i] = 0;
+ if ( fCompNew )
+ fprintf( pFile, " NOT(" );
+ else
+ fprintf( pFile, " " );
+ if ( fShortNames )
+ fprintf( pFile, "%d", pInput->S->index );
+ else
+ fprintf( pFile, "%s", pInputNames[pInput->S->index] );
+ if ( fCompNew )
+ fprintf( pFile, ")" );
+ }
+ else
+ {
+ pInputNums[i] = (*pSigCounter)++;
+ fprintf( pFile, " <%d>", pInputNums[i] );
+ }
+ }
+ fprintf( pFile, " )\n" );
+ // call recursively for the following blocks
+ for ( i = 0; i < pNode->nDecs; i++ )
+ if ( pInputNums[i] )
+ {
+ pInput = Dsd_Regular( pNode->pDecs[i] );
+ fCompNew = (int)( pInput != pNode->pDecs[i] );
+ sprintf( Buffer, "<%d>", pInputNums[i] );
+ Dsd_TreePrint_rec( pFile, Dsd_Regular( pNode->pDecs[i] ), fCompNew, pInputNames, Buffer, nOffset + 6, pSigCounter, fShortNames );
+ }
+ }
+ free( pInputNums );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Retuns the function of one node of the decomposition tree.]
+
+ Description [This is the old procedure. It is now superceded by the
+ procedure Dsd_TreeGetPrimeFunction() found in "dsdLocal.c".]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdNode * Dsd_TreeGetPrimeFunctionOld( DdManager * dd, Dsd_Node_t * pNode, int fRemap )
+{
+ DdNode * bCof0, * bCof1, * bCube0, * bCube1, * bNewFunc, * bTemp;
+ int i;
+ int fAllBuffs = 1;
+ int * pPermute;
+
+ pPermute = ALLOC( int, dd->size );
+
+ assert( pNode );
+ assert( !Dsd_IsComplement( pNode ) );
+ assert( pNode->Type == DSD_NODE_PRIME );
+
+ // transform the function of this block to depend on inputs
+ // corresponding to the formal inputs
+
+ // first, substitute those inputs that have some blocks associated with them
+ // second, remap the inputs to the top of the manager (then, it is easy to output them)
+
+ // start the function
+ bNewFunc = pNode->G; Cudd_Ref( bNewFunc );
+ // go over all primary inputs
+ for ( i = 0; i < pNode->nDecs; i++ )
+ if ( pNode->pDecs[i]->Type != DSD_NODE_BUF ) // remap only if it is not the buffer
+ {
+ bCube0 = Extra_bddFindOneCube( dd, Cudd_Not(pNode->pDecs[i]->G) ); Cudd_Ref( bCube0 );
+ bCof0 = Cudd_Cofactor( dd, bNewFunc, bCube0 ); Cudd_Ref( bCof0 );
+ Cudd_RecursiveDeref( dd, bCube0 );
+
+ bCube1 = Extra_bddFindOneCube( dd, pNode->pDecs[i]->G ); Cudd_Ref( bCube1 );
+ bCof1 = Cudd_Cofactor( dd, bNewFunc, bCube1 ); Cudd_Ref( bCof1 );
+ Cudd_RecursiveDeref( dd, bCube1 );
+
+ Cudd_RecursiveDeref( dd, bNewFunc );
+
+ // use the variable in the i-th level of the manager
+// bNewFunc = Cudd_bddIte( dd, dd->vars[dd->invperm[i]],bCof1,bCof0 ); Cudd_Ref( bNewFunc );
+ // use the first variale in the support of the component
+ bNewFunc = Cudd_bddIte( dd, dd->vars[pNode->pDecs[i]->S->index],bCof1,bCof0 ); Cudd_Ref( bNewFunc );
+ Cudd_RecursiveDeref( dd, bCof0 );
+ Cudd_RecursiveDeref( dd, bCof1 );
+ }
+
+ if ( fRemap )
+ {
+ // remap the function to the top of the manager
+ // remap the function to the first variables of the manager
+ for ( i = 0; i < pNode->nDecs; i++ )
+ // Permute[ pNode->pDecs[i]->S->index ] = dd->invperm[i];
+ pPermute[ pNode->pDecs[i]->S->index ] = i;
+
+ bNewFunc = Cudd_bddPermute( dd, bTemp = bNewFunc, pPermute ); Cudd_Ref( bNewFunc );
+ Cudd_RecursiveDeref( dd, bTemp );
+ }
+
+ Cudd_Deref( bNewFunc );
+ free( pPermute );
+ return bNewFunc;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
diff --git a/src/bdd/dsd/module.make b/src/bdd/dsd/module.make
new file mode 100644
index 00000000..f6418492
--- /dev/null
+++ b/src/bdd/dsd/module.make
@@ -0,0 +1,6 @@
+SRC += bdd\dsd\dsdApi.c \
+ bdd\dsd\dsdCheck.c \
+ bdd\dsd\dsdLocal.c \
+ bdd\dsd\dsdMan.c \
+ bdd\dsd\dsdProc.c \
+ bdd\dsd\dsdTree.c
diff --git a/src/bdd/epd/epd.c b/src/bdd/epd/epd.c
new file mode 100644
index 00000000..a843b986
--- /dev/null
+++ b/src/bdd/epd/epd.c
@@ -0,0 +1,1314 @@
+/**CFile***********************************************************************
+
+ FileName [epd.c]
+
+ PackageName [epd]
+
+ Synopsis [Arithmetic functions with extended double precision.]
+
+ Description []
+
+ SeeAlso []
+
+ Author [In-Ho Moon]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+ Revision [$Id: epd.c,v 1.1.1.1 2003/02/24 22:23:57 wjiang Exp $]
+
+******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "util.h"
+#include "epd.h"
+
+
+/**Function********************************************************************
+
+ Synopsis [Allocates an EpDouble struct.]
+
+ Description [Allocates an EpDouble struct.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+EpDouble *
+EpdAlloc()
+{
+ EpDouble *epd;
+
+ epd = ALLOC(EpDouble, 1);
+ return(epd);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Compares two EpDouble struct.]
+
+ Description [Compares two EpDouble struct.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int
+EpdCmp(const char *key1, const char *key2)
+{
+ EpDouble *epd1 = (EpDouble *) key1;
+ EpDouble *epd2 = (EpDouble *) key2;
+ if (epd1->type.value != epd2->type.value ||
+ epd1->exponent != epd2->exponent) {
+ return(1);
+ }
+ return(0);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees an EpDouble struct.]
+
+ Description [Frees an EpDouble struct.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdFree(EpDouble *epd)
+{
+ FREE(epd);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Multiplies two arbitrary precision double values.]
+
+ Description [Multiplies two arbitrary precision double values.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdGetString(EpDouble *epd, char *str)
+{
+ double value;
+ int exponent;
+ char *pos;
+
+ if (IsNanDouble(epd->type.value)) {
+ sprintf(str, "NaN");
+ return;
+ } else if (IsInfDouble(epd->type.value)) {
+ if (epd->type.bits.sign == 1)
+ sprintf(str, "-Inf");
+ else
+ sprintf(str, "Inf");
+ return;
+ }
+
+ assert(epd->type.bits.exponent == EPD_MAX_BIN ||
+ epd->type.bits.exponent == 0);
+
+ EpdGetValueAndDecimalExponent(epd, &value, &exponent);
+ sprintf(str, "%e", value);
+ pos = strstr(str, "e");
+ if (exponent >= 0) {
+ if (exponent < 10)
+ sprintf(pos + 1, "+0%d", exponent);
+ else
+ sprintf(pos + 1, "+%d", exponent);
+ } else {
+ exponent *= -1;
+ if (exponent < 10)
+ sprintf(pos + 1, "-0%d", exponent);
+ else
+ sprintf(pos + 1, "-%d", exponent);
+ }
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Converts double to EpDouble struct.]
+
+ Description [Converts double to EpDouble struct.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdConvert(double value, EpDouble *epd)
+{
+ epd->type.value = value;
+ epd->exponent = 0;
+ EpdNormalize(epd);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Multiplies two arbitrary precision double values.]
+
+ Description [Multiplies two arbitrary precision double values.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdMultiply(EpDouble *epd1, double value)
+{
+ EpDouble epd2;
+ double tmp;
+ int exponent;
+
+ if (EpdIsNan(epd1) || IsNanDouble(value)) {
+ EpdMakeNan(epd1);
+ return;
+ } else if (EpdIsInf(epd1) || IsInfDouble(value)) {
+ int sign;
+
+ EpdConvert(value, &epd2);
+ sign = epd1->type.bits.sign ^ epd2.type.bits.sign;
+ EpdMakeInf(epd1, sign);
+ return;
+ }
+
+ assert(epd1->type.bits.exponent == EPD_MAX_BIN);
+
+ EpdConvert(value, &epd2);
+ tmp = epd1->type.value * epd2.type.value;
+ exponent = epd1->exponent + epd2.exponent;
+ epd1->type.value = tmp;
+ epd1->exponent = exponent;
+ EpdNormalize(epd1);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Multiplies two arbitrary precision double values.]
+
+ Description [Multiplies two arbitrary precision double values.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdMultiply2(EpDouble *epd1, EpDouble *epd2)
+{
+ double value;
+ int exponent;
+
+ if (EpdIsNan(epd1) || EpdIsNan(epd2)) {
+ EpdMakeNan(epd1);
+ return;
+ } else if (EpdIsInf(epd1) || EpdIsInf(epd2)) {
+ int sign;
+
+ sign = epd1->type.bits.sign ^ epd2->type.bits.sign;
+ EpdMakeInf(epd1, sign);
+ return;
+ }
+
+ assert(epd1->type.bits.exponent == EPD_MAX_BIN);
+ assert(epd2->type.bits.exponent == EPD_MAX_BIN);
+
+ value = epd1->type.value * epd2->type.value;
+ exponent = epd1->exponent + epd2->exponent;
+ epd1->type.value = value;
+ epd1->exponent = exponent;
+ EpdNormalize(epd1);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Multiplies two arbitrary precision double values.]
+
+ Description [Multiplies two arbitrary precision double values.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdMultiply2Decimal(EpDouble *epd1, EpDouble *epd2)
+{
+ double value;
+ int exponent;
+
+ if (EpdIsNan(epd1) || EpdIsNan(epd2)) {
+ EpdMakeNan(epd1);
+ return;
+ } else if (EpdIsInf(epd1) || EpdIsInf(epd2)) {
+ int sign;
+
+ sign = epd1->type.bits.sign ^ epd2->type.bits.sign;
+ EpdMakeInf(epd1, sign);
+ return;
+ }
+
+ value = epd1->type.value * epd2->type.value;
+ exponent = epd1->exponent + epd2->exponent;
+ epd1->type.value = value;
+ epd1->exponent = exponent;
+ EpdNormalizeDecimal(epd1);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Multiplies two arbitrary precision double values.]
+
+ Description [Multiplies two arbitrary precision double values.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdMultiply3(EpDouble *epd1, EpDouble *epd2, EpDouble *epd3)
+{
+ if (EpdIsNan(epd1) || EpdIsNan(epd2)) {
+ EpdMakeNan(epd1);
+ return;
+ } else if (EpdIsInf(epd1) || EpdIsInf(epd2)) {
+ int sign;
+
+ sign = epd1->type.bits.sign ^ epd2->type.bits.sign;
+ EpdMakeInf(epd3, sign);
+ return;
+ }
+
+ assert(epd1->type.bits.exponent == EPD_MAX_BIN);
+ assert(epd2->type.bits.exponent == EPD_MAX_BIN);
+
+ epd3->type.value = epd1->type.value * epd2->type.value;
+ epd3->exponent = epd1->exponent + epd2->exponent;
+ EpdNormalize(epd3);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Multiplies two arbitrary precision double values.]
+
+ Description [Multiplies two arbitrary precision double values.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdMultiply3Decimal(EpDouble *epd1, EpDouble *epd2, EpDouble *epd3)
+{
+ if (EpdIsNan(epd1) || EpdIsNan(epd2)) {
+ EpdMakeNan(epd1);
+ return;
+ } else if (EpdIsInf(epd1) || EpdIsInf(epd2)) {
+ int sign;
+
+ sign = epd1->type.bits.sign ^ epd2->type.bits.sign;
+ EpdMakeInf(epd3, sign);
+ return;
+ }
+
+ epd3->type.value = epd1->type.value * epd2->type.value;
+ epd3->exponent = epd1->exponent + epd2->exponent;
+ EpdNormalizeDecimal(epd3);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Divides two arbitrary precision double values.]
+
+ Description [Divides two arbitrary precision double values.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdDivide(EpDouble *epd1, double value)
+{
+ EpDouble epd2;
+ double tmp;
+ int exponent;
+
+ if (EpdIsNan(epd1) || IsNanDouble(value)) {
+ EpdMakeNan(epd1);
+ return;
+ } else if (EpdIsInf(epd1) || IsInfDouble(value)) {
+ int sign;
+
+ EpdConvert(value, &epd2);
+ if (EpdIsInf(epd1) && IsInfDouble(value)) {
+ EpdMakeNan(epd1);
+ } else if (EpdIsInf(epd1)) {
+ sign = epd1->type.bits.sign ^ epd2.type.bits.sign;
+ EpdMakeInf(epd1, sign);
+ } else {
+ sign = epd1->type.bits.sign ^ epd2.type.bits.sign;
+ EpdMakeZero(epd1, sign);
+ }
+ return;
+ }
+
+ if (value == 0.0) {
+ EpdMakeNan(epd1);
+ return;
+ }
+
+ assert(epd1->type.bits.exponent == EPD_MAX_BIN);
+
+ EpdConvert(value, &epd2);
+ tmp = epd1->type.value / epd2.type.value;
+ exponent = epd1->exponent - epd2.exponent;
+ epd1->type.value = tmp;
+ epd1->exponent = exponent;
+ EpdNormalize(epd1);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Divides two arbitrary precision double values.]
+
+ Description [Divides two arbitrary precision double values.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdDivide2(EpDouble *epd1, EpDouble *epd2)
+{
+ double value;
+ int exponent;
+
+ if (EpdIsNan(epd1) || EpdIsNan(epd2)) {
+ EpdMakeNan(epd1);
+ return;
+ } else if (EpdIsInf(epd1) || EpdIsInf(epd2)) {
+ int sign;
+
+ if (EpdIsInf(epd1) && EpdIsInf(epd2)) {
+ EpdMakeNan(epd1);
+ } else if (EpdIsInf(epd1)) {
+ sign = epd1->type.bits.sign ^ epd2->type.bits.sign;
+ EpdMakeInf(epd1, sign);
+ } else {
+ sign = epd1->type.bits.sign ^ epd2->type.bits.sign;
+ EpdMakeZero(epd1, sign);
+ }
+ return;
+ }
+
+ if (epd2->type.value == 0.0) {
+ EpdMakeNan(epd1);
+ return;
+ }
+
+ assert(epd1->type.bits.exponent == EPD_MAX_BIN);
+ assert(epd2->type.bits.exponent == EPD_MAX_BIN);
+
+ value = epd1->type.value / epd2->type.value;
+ exponent = epd1->exponent - epd2->exponent;
+ epd1->type.value = value;
+ epd1->exponent = exponent;
+ EpdNormalize(epd1);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Divides two arbitrary precision double values.]
+
+ Description [Divides two arbitrary precision double values.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdDivide3(EpDouble *epd1, EpDouble *epd2, EpDouble *epd3)
+{
+ if (EpdIsNan(epd1) || EpdIsNan(epd2)) {
+ EpdMakeNan(epd3);
+ return;
+ } else if (EpdIsInf(epd1) || EpdIsInf(epd2)) {
+ int sign;
+
+ if (EpdIsInf(epd1) && EpdIsInf(epd2)) {
+ EpdMakeNan(epd3);
+ } else if (EpdIsInf(epd1)) {
+ sign = epd1->type.bits.sign ^ epd2->type.bits.sign;
+ EpdMakeInf(epd3, sign);
+ } else {
+ sign = epd1->type.bits.sign ^ epd2->type.bits.sign;
+ EpdMakeZero(epd3, sign);
+ }
+ return;
+ }
+
+ if (epd2->type.value == 0.0) {
+ EpdMakeNan(epd3);
+ return;
+ }
+
+ assert(epd1->type.bits.exponent == EPD_MAX_BIN);
+ assert(epd2->type.bits.exponent == EPD_MAX_BIN);
+
+ epd3->type.value = epd1->type.value / epd2->type.value;
+ epd3->exponent = epd1->exponent - epd2->exponent;
+ EpdNormalize(epd3);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Adds two arbitrary precision double values.]
+
+ Description [Adds two arbitrary precision double values.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdAdd(EpDouble *epd1, double value)
+{
+ EpDouble epd2;
+ double tmp;
+ int exponent, diff;
+
+ if (EpdIsNan(epd1) || IsNanDouble(value)) {
+ EpdMakeNan(epd1);
+ return;
+ } else if (EpdIsInf(epd1) || IsInfDouble(value)) {
+ int sign;
+
+ EpdConvert(value, &epd2);
+ if (EpdIsInf(epd1) && IsInfDouble(value)) {
+ sign = epd1->type.bits.sign ^ epd2.type.bits.sign;
+ if (sign == 1)
+ EpdMakeNan(epd1);
+ } else if (EpdIsInf(&epd2)) {
+ EpdCopy(&epd2, epd1);
+ }
+ return;
+ }
+
+ assert(epd1->type.bits.exponent == EPD_MAX_BIN);
+
+ EpdConvert(value, &epd2);
+ if (epd1->exponent > epd2.exponent) {
+ diff = epd1->exponent - epd2.exponent;
+ if (diff <= EPD_MAX_BIN)
+ tmp = epd1->type.value + epd2.type.value / pow((double)2.0, (double)diff);
+ else
+ tmp = epd1->type.value;
+ exponent = epd1->exponent;
+ } else if (epd1->exponent < epd2.exponent) {
+ diff = epd2.exponent - epd1->exponent;
+ if (diff <= EPD_MAX_BIN)
+ tmp = epd1->type.value / pow((double)2.0, (double)diff) + epd2.type.value;
+ else
+ tmp = epd2.type.value;
+ exponent = epd2.exponent;
+ } else {
+ tmp = epd1->type.value + epd2.type.value;
+ exponent = epd1->exponent;
+ }
+ epd1->type.value = tmp;
+ epd1->exponent = exponent;
+ EpdNormalize(epd1);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Adds two arbitrary precision double values.]
+
+ Description [Adds two arbitrary precision double values.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdAdd2(EpDouble *epd1, EpDouble *epd2)
+{
+ double value;
+ int exponent, diff;
+
+ if (EpdIsNan(epd1) || EpdIsNan(epd2)) {
+ EpdMakeNan(epd1);
+ return;
+ } else if (EpdIsInf(epd1) || EpdIsInf(epd2)) {
+ int sign;
+
+ if (EpdIsInf(epd1) && EpdIsInf(epd2)) {
+ sign = epd1->type.bits.sign ^ epd2->type.bits.sign;
+ if (sign == 1)
+ EpdMakeNan(epd1);
+ } else if (EpdIsInf(epd2)) {
+ EpdCopy(epd2, epd1);
+ }
+ return;
+ }
+
+ assert(epd1->type.bits.exponent == EPD_MAX_BIN);
+ assert(epd2->type.bits.exponent == EPD_MAX_BIN);
+
+ if (epd1->exponent > epd2->exponent) {
+ diff = epd1->exponent - epd2->exponent;
+ if (diff <= EPD_MAX_BIN) {
+ value = epd1->type.value +
+ epd2->type.value / pow((double)2.0, (double)diff);
+ } else
+ value = epd1->type.value;
+ exponent = epd1->exponent;
+ } else if (epd1->exponent < epd2->exponent) {
+ diff = epd2->exponent - epd1->exponent;
+ if (diff <= EPD_MAX_BIN) {
+ value = epd1->type.value / pow((double)2.0, (double)diff) +
+ epd2->type.value;
+ } else
+ value = epd2->type.value;
+ exponent = epd2->exponent;
+ } else {
+ value = epd1->type.value + epd2->type.value;
+ exponent = epd1->exponent;
+ }
+ epd1->type.value = value;
+ epd1->exponent = exponent;
+ EpdNormalize(epd1);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Adds two arbitrary precision double values.]
+
+ Description [Adds two arbitrary precision double values.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdAdd3(EpDouble *epd1, EpDouble *epd2, EpDouble *epd3)
+{
+ double value;
+ int exponent, diff;
+
+ if (EpdIsNan(epd1) || EpdIsNan(epd2)) {
+ EpdMakeNan(epd3);
+ return;
+ } else if (EpdIsInf(epd1) || EpdIsInf(epd2)) {
+ int sign;
+
+ if (EpdIsInf(epd1) && EpdIsInf(epd2)) {
+ sign = epd1->type.bits.sign ^ epd2->type.bits.sign;
+ if (sign == 1)
+ EpdMakeNan(epd3);
+ else
+ EpdCopy(epd1, epd3);
+ } else if (EpdIsInf(epd1)) {
+ EpdCopy(epd1, epd3);
+ } else {
+ EpdCopy(epd2, epd3);
+ }
+ return;
+ }
+
+ assert(epd1->type.bits.exponent == EPD_MAX_BIN);
+ assert(epd2->type.bits.exponent == EPD_MAX_BIN);
+
+ if (epd1->exponent > epd2->exponent) {
+ diff = epd1->exponent - epd2->exponent;
+ if (diff <= EPD_MAX_BIN) {
+ value = epd1->type.value +
+ epd2->type.value / pow((double)2.0, (double)diff);
+ } else
+ value = epd1->type.value;
+ exponent = epd1->exponent;
+ } else if (epd1->exponent < epd2->exponent) {
+ diff = epd2->exponent - epd1->exponent;
+ if (diff <= EPD_MAX_BIN) {
+ value = epd1->type.value / pow((double)2.0, (double)diff) +
+ epd2->type.value;
+ } else
+ value = epd2->type.value;
+ exponent = epd2->exponent;
+ } else {
+ value = epd1->type.value + epd2->type.value;
+ exponent = epd1->exponent;
+ }
+ epd3->type.value = value;
+ epd3->exponent = exponent;
+ EpdNormalize(epd3);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Subtracts two arbitrary precision double values.]
+
+ Description [Subtracts two arbitrary precision double values.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdSubtract(EpDouble *epd1, double value)
+{
+ EpDouble epd2;
+ double tmp;
+ int exponent, diff;
+
+ if (EpdIsNan(epd1) || IsNanDouble(value)) {
+ EpdMakeNan(epd1);
+ return;
+ } else if (EpdIsInf(epd1) || IsInfDouble(value)) {
+ int sign;
+
+ EpdConvert(value, &epd2);
+ if (EpdIsInf(epd1) && IsInfDouble(value)) {
+ sign = epd1->type.bits.sign ^ epd2.type.bits.sign;
+ if (sign == 0)
+ EpdMakeNan(epd1);
+ } else if (EpdIsInf(&epd2)) {
+ EpdCopy(&epd2, epd1);
+ }
+ return;
+ }
+
+ assert(epd1->type.bits.exponent == EPD_MAX_BIN);
+
+ EpdConvert(value, &epd2);
+ if (epd1->exponent > epd2.exponent) {
+ diff = epd1->exponent - epd2.exponent;
+ if (diff <= EPD_MAX_BIN)
+ tmp = epd1->type.value - epd2.type.value / pow((double)2.0, (double)diff);
+ else
+ tmp = epd1->type.value;
+ exponent = epd1->exponent;
+ } else if (epd1->exponent < epd2.exponent) {
+ diff = epd2.exponent - epd1->exponent;
+ if (diff <= EPD_MAX_BIN)
+ tmp = epd1->type.value / pow((double)2.0, (double)diff) - epd2.type.value;
+ else
+ tmp = epd2.type.value * (double)(-1.0);
+ exponent = epd2.exponent;
+ } else {
+ tmp = epd1->type.value - epd2.type.value;
+ exponent = epd1->exponent;
+ }
+ epd1->type.value = tmp;
+ epd1->exponent = exponent;
+ EpdNormalize(epd1);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Subtracts two arbitrary precision double values.]
+
+ Description [Subtracts two arbitrary precision double values.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdSubtract2(EpDouble *epd1, EpDouble *epd2)
+{
+ double value;
+ int exponent, diff;
+
+ if (EpdIsNan(epd1) || EpdIsNan(epd2)) {
+ EpdMakeNan(epd1);
+ return;
+ } else if (EpdIsInf(epd1) || EpdIsInf(epd2)) {
+ int sign;
+
+ if (EpdIsInf(epd1) && EpdIsInf(epd2)) {
+ sign = epd1->type.bits.sign ^ epd2->type.bits.sign;
+ if (sign == 0)
+ EpdMakeNan(epd1);
+ } else if (EpdIsInf(epd2)) {
+ EpdCopy(epd2, epd1);
+ }
+ return;
+ }
+
+ assert(epd1->type.bits.exponent == EPD_MAX_BIN);
+ assert(epd2->type.bits.exponent == EPD_MAX_BIN);
+
+ if (epd1->exponent > epd2->exponent) {
+ diff = epd1->exponent - epd2->exponent;
+ if (diff <= EPD_MAX_BIN) {
+ value = epd1->type.value -
+ epd2->type.value / pow((double)2.0, (double)diff);
+ } else
+ value = epd1->type.value;
+ exponent = epd1->exponent;
+ } else if (epd1->exponent < epd2->exponent) {
+ diff = epd2->exponent - epd1->exponent;
+ if (diff <= EPD_MAX_BIN) {
+ value = epd1->type.value / pow((double)2.0, (double)diff) -
+ epd2->type.value;
+ } else
+ value = epd2->type.value * (double)(-1.0);
+ exponent = epd2->exponent;
+ } else {
+ value = epd1->type.value - epd2->type.value;
+ exponent = epd1->exponent;
+ }
+ epd1->type.value = value;
+ epd1->exponent = exponent;
+ EpdNormalize(epd1);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Subtracts two arbitrary precision double values.]
+
+ Description [Subtracts two arbitrary precision double values.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdSubtract3(EpDouble *epd1, EpDouble *epd2, EpDouble *epd3)
+{
+ double value;
+ int exponent, diff;
+
+ if (EpdIsNan(epd1) || EpdIsNan(epd2)) {
+ EpdMakeNan(epd3);
+ return;
+ } else if (EpdIsInf(epd1) || EpdIsInf(epd2)) {
+ int sign;
+
+ if (EpdIsInf(epd1) && EpdIsInf(epd2)) {
+ sign = epd1->type.bits.sign ^ epd2->type.bits.sign;
+ if (sign == 0)
+ EpdCopy(epd1, epd3);
+ else
+ EpdMakeNan(epd3);
+ } else if (EpdIsInf(epd1)) {
+ EpdCopy(epd1, epd1);
+ } else {
+ sign = epd2->type.bits.sign ^ 0x1;
+ EpdMakeInf(epd3, sign);
+ }
+ return;
+ }
+
+ assert(epd1->type.bits.exponent == EPD_MAX_BIN);
+ assert(epd2->type.bits.exponent == EPD_MAX_BIN);
+
+ if (epd1->exponent > epd2->exponent) {
+ diff = epd1->exponent - epd2->exponent;
+ if (diff <= EPD_MAX_BIN) {
+ value = epd1->type.value -
+ epd2->type.value / pow((double)2.0, (double)diff);
+ } else
+ value = epd1->type.value;
+ exponent = epd1->exponent;
+ } else if (epd1->exponent < epd2->exponent) {
+ diff = epd2->exponent - epd1->exponent;
+ if (diff <= EPD_MAX_BIN) {
+ value = epd1->type.value / pow((double)2.0, (double)diff) -
+ epd2->type.value;
+ } else
+ value = epd2->type.value * (double)(-1.0);
+ exponent = epd2->exponent;
+ } else {
+ value = epd1->type.value - epd2->type.value;
+ exponent = epd1->exponent;
+ }
+ epd3->type.value = value;
+ epd3->exponent = exponent;
+ EpdNormalize(epd3);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes arbitrary precision pow of base 2.]
+
+ Description [Computes arbitrary precision pow of base 2.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdPow2(int n, EpDouble *epd)
+{
+ if (n <= EPD_MAX_BIN) {
+ EpdConvert(pow((double)2.0, (double)n), epd);
+ } else {
+ EpDouble epd1, epd2;
+ int n1, n2;
+
+ n1 = n / 2;
+ n2 = n - n1;
+ EpdPow2(n1, &epd1);
+ EpdPow2(n2, &epd2);
+ EpdMultiply3(&epd1, &epd2, epd);
+ }
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes arbitrary precision pow of base 2.]
+
+ Description [Computes arbitrary precision pow of base 2.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdPow2Decimal(int n, EpDouble *epd)
+{
+ if (n <= EPD_MAX_BIN) {
+ epd->type.value = pow((double)2.0, (double)n);
+ epd->exponent = 0;
+ EpdNormalizeDecimal(epd);
+ } else {
+ EpDouble epd1, epd2;
+ int n1, n2;
+
+ n1 = n / 2;
+ n2 = n - n1;
+ EpdPow2Decimal(n1, &epd1);
+ EpdPow2Decimal(n2, &epd2);
+ EpdMultiply3Decimal(&epd1, &epd2, epd);
+ }
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Normalize an arbitrary precision double value.]
+
+ Description [Normalize an arbitrary precision double value.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdNormalize(EpDouble *epd)
+{
+ int exponent;
+
+ if (IsNanOrInfDouble(epd->type.value)) {
+ epd->exponent = 0;
+ return;
+ }
+
+ exponent = EpdGetExponent(epd->type.value);
+ if (exponent == EPD_MAX_BIN)
+ return;
+ exponent -= EPD_MAX_BIN;
+ epd->type.bits.exponent = EPD_MAX_BIN;
+ epd->exponent += exponent;
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Normalize an arbitrary precision double value.]
+
+ Description [Normalize an arbitrary precision double value.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdNormalizeDecimal(EpDouble *epd)
+{
+ int exponent;
+
+ if (IsNanOrInfDouble(epd->type.value)) {
+ epd->exponent = 0;
+ return;
+ }
+
+ exponent = EpdGetExponentDecimal(epd->type.value);
+ epd->type.value /= pow((double)10.0, (double)exponent);
+ epd->exponent += exponent;
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns value and decimal exponent of EpDouble.]
+
+ Description [Returns value and decimal exponent of EpDouble.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdGetValueAndDecimalExponent(EpDouble *epd, double *value, int *exponent)
+{
+ EpDouble epd1, epd2;
+
+ if (EpdIsNanOrInf(epd))
+ return;
+
+ if (EpdIsZero(epd)) {
+ *value = 0.0;
+ *exponent = 0;
+ return;
+ }
+
+ epd1.type.value = epd->type.value;
+ epd1.exponent = 0;
+ EpdPow2Decimal(epd->exponent, &epd2);
+ EpdMultiply2Decimal(&epd1, &epd2);
+
+ *value = epd1.type.value;
+ *exponent = epd1.exponent;
+}
+
+/**Function********************************************************************
+
+ Synopsis [Returns the exponent value of a double.]
+
+ Description [Returns the exponent value of a double.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int
+EpdGetExponent(double value)
+{
+ int exponent;
+ EpDouble epd;
+
+ epd.type.value = value;
+ exponent = epd.type.bits.exponent;
+ return(exponent);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns the decimal exponent value of a double.]
+
+ Description [Returns the decimal exponent value of a double.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int
+EpdGetExponentDecimal(double value)
+{
+ char *pos, str[24];
+ int exponent;
+
+ sprintf(str, "%E", value);
+ pos = strstr(str, "E");
+ sscanf(pos, "E%d", &exponent);
+ return(exponent);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Makes EpDouble Inf.]
+
+ Description [Makes EpDouble Inf.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdMakeInf(EpDouble *epd, int sign)
+{
+ epd->type.bits.mantissa1 = 0;
+ epd->type.bits.mantissa0 = 0;
+ epd->type.bits.exponent = EPD_EXP_INF;
+ epd->type.bits.sign = sign;
+ epd->exponent = 0;
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Makes EpDouble Zero.]
+
+ Description [Makes EpDouble Zero.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdMakeZero(EpDouble *epd, int sign)
+{
+ epd->type.bits.mantissa1 = 0;
+ epd->type.bits.mantissa0 = 0;
+ epd->type.bits.exponent = 0;
+ epd->type.bits.sign = sign;
+ epd->exponent = 0;
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Makes EpDouble NaN.]
+
+ Description [Makes EpDouble NaN.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdMakeNan(EpDouble *epd)
+{
+ epd->type.nan.mantissa1 = 0;
+ epd->type.nan.mantissa0 = 0;
+ epd->type.nan.quiet_bit = 1;
+ epd->type.nan.exponent = EPD_EXP_INF;
+ epd->type.nan.sign = 1;
+ epd->exponent = 0;
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Copies a EpDouble struct.]
+
+ Description [Copies a EpDouble struct.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void
+EpdCopy(EpDouble *from, EpDouble *to)
+{
+ to->type.value = from->type.value;
+ to->exponent = from->exponent;
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether the value is Inf.]
+
+ Description [Checks whether the value is Inf.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int
+EpdIsInf(EpDouble *epd)
+{
+ return(IsInfDouble(epd->type.value));
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether the value is Zero.]
+
+ Description [Checks whether the value is Zero.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int
+EpdIsZero(EpDouble *epd)
+{
+ if (epd->type.value == 0.0)
+ return(1);
+ else
+ return(0);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether the value is NaN.]
+
+ Description [Checks whether the value is NaN.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int
+EpdIsNan(EpDouble *epd)
+{
+ return(IsNanDouble(epd->type.value));
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether the value is NaN or Inf.]
+
+ Description [Checks whether the value is NaN or Inf.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int
+EpdIsNanOrInf(EpDouble *epd)
+{
+ return(IsNanOrInfDouble(epd->type.value));
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether the value is Inf.]
+
+ Description [Checks whether the value is Inf.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int
+IsInfDouble(double value)
+{
+ IeeeDouble *ptr = (IeeeDouble *)(&value);
+
+ if (ptr->exponent == EPD_EXP_INF &&
+ ptr->mantissa0 == 0 &&
+ ptr->mantissa1 == 0) {
+ if (ptr->sign == 0)
+ return(1);
+ else
+ return(-1);
+ }
+ return(0);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether the value is NaN.]
+
+ Description [Checks whether the value is NaN.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int
+IsNanDouble(double value)
+{
+ IeeeNan *ptr = (IeeeNan *)(&value);
+
+ if (ptr->exponent == EPD_EXP_INF &&
+ ptr->sign == 1 &&
+ ptr->quiet_bit == 1 &&
+ ptr->mantissa0 == 0 &&
+ ptr->mantissa1 == 0) {
+ return(1);
+ }
+ return(0);
+}
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks whether the value is NaN or Inf.]
+
+ Description [Checks whether the value is NaN or Inf.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int
+IsNanOrInfDouble(double value)
+{
+ IeeeNan *ptr = (IeeeNan *)(&value);
+
+ if (ptr->exponent == EPD_EXP_INF &&
+ ptr->mantissa0 == 0 &&
+ ptr->mantissa1 == 0 &&
+ (ptr->sign == 1 || ptr->quiet_bit == 0)) {
+ return(1);
+ }
+ return(0);
+}
diff --git a/src/bdd/epd/epd.h b/src/bdd/epd/epd.h
new file mode 100644
index 00000000..66db80e3
--- /dev/null
+++ b/src/bdd/epd/epd.h
@@ -0,0 +1,160 @@
+/**CHeaderFile*****************************************************************
+
+ FileName [epd.h]
+
+ PackageName [epd]
+
+ Synopsis [The University of Colorado extended double precision package.]
+
+ Description [arithmetic functions with extended double precision.]
+
+ SeeAlso []
+
+ Author [In-Ho Moon]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+ Revision [$Id: epd.h,v 1.1.1.1 2003/02/24 22:23:57 wjiang Exp $]
+
+******************************************************************************/
+
+#ifndef _EPD
+#define _EPD
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define EPD_MAX_BIN 1023
+#define EPD_MAX_DEC 308
+#define EPD_EXP_INF 0x7ff
+
+/*---------------------------------------------------------------------------*/
+/* Structure declarations */
+/*---------------------------------------------------------------------------*/
+
+/**Struct**********************************************************************
+
+ Synopsis [IEEE double struct.]
+
+ Description [IEEE double struct.]
+
+ SeeAlso []
+
+******************************************************************************/
+#ifdef EPD_BIG_ENDIAN
+struct IeeeDoubleStruct { /* BIG_ENDIAN */
+ unsigned int sign: 1;
+ unsigned int exponent: 11;
+ unsigned int mantissa0: 20;
+ unsigned int mantissa1: 32;
+};
+#else
+struct IeeeDoubleStruct { /* LITTLE_ENDIAN */
+ unsigned int mantissa1: 32;
+ unsigned int mantissa0: 20;
+ unsigned int exponent: 11;
+ unsigned int sign: 1;
+};
+#endif
+
+/**Struct**********************************************************************
+
+ Synopsis [IEEE double NaN struct.]
+
+ Description [IEEE double NaN struct.]
+
+ SeeAlso []
+
+******************************************************************************/
+#ifdef EPD_BIG_ENDIAN
+struct IeeeNanStruct { /* BIG_ENDIAN */
+ unsigned int sign: 1;
+ unsigned int exponent: 11;
+ unsigned int quiet_bit: 1;
+ unsigned int mantissa0: 19;
+ unsigned int mantissa1: 32;
+};
+#else
+struct IeeeNanStruct { /* LITTLE_ENDIAN */
+ unsigned int mantissa1: 32;
+ unsigned int mantissa0: 19;
+ unsigned int quiet_bit: 1;
+ unsigned int exponent: 11;
+ unsigned int sign: 1;
+};
+#endif
+
+/**Struct**********************************************************************
+
+ Synopsis [Extended precision double to keep very large value.]
+
+ Description [Extended precision double to keep very large value.]
+
+ SeeAlso []
+
+******************************************************************************/
+struct EpDoubleStruct {
+ union {
+ double value;
+ struct IeeeDoubleStruct bits;
+ struct IeeeNanStruct nan;
+ } type;
+ int exponent;
+};
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+typedef struct EpDoubleStruct EpDouble;
+typedef struct IeeeDoubleStruct IeeeDouble;
+typedef struct IeeeNanStruct IeeeNan;
+
+
+/*---------------------------------------------------------------------------*/
+/* Function prototypes */
+/*---------------------------------------------------------------------------*/
+
+EpDouble *EpdAlloc();
+int EpdCmp(const char *key1, const char *key2);
+void EpdFree(EpDouble *epd);
+void EpdGetString(EpDouble *epd, char *str);
+void EpdConvert(double value, EpDouble *epd);
+void EpdMultiply(EpDouble *epd1, double value);
+void EpdMultiply2(EpDouble *epd1, EpDouble *epd2);
+void EpdMultiply2Decimal(EpDouble *epd1, EpDouble *epd2);
+void EpdMultiply3(EpDouble *epd1, EpDouble *epd2, EpDouble *epd3);
+void EpdMultiply3Decimal(EpDouble *epd1, EpDouble *epd2, EpDouble *epd3);
+void EpdDivide(EpDouble *epd1, double value);
+void EpdDivide2(EpDouble *epd1, EpDouble *epd2);
+void EpdDivide3(EpDouble *epd1, EpDouble *epd2, EpDouble *epd3);
+void EpdAdd(EpDouble *epd1, double value);
+void EpdAdd2(EpDouble *epd1, EpDouble *epd2);
+void EpdAdd3(EpDouble *epd1, EpDouble *epd2, EpDouble *epd3);
+void EpdSubtract(EpDouble *epd1, double value);
+void EpdSubtract2(EpDouble *epd1, EpDouble *epd2);
+void EpdSubtract3(EpDouble *epd1, EpDouble *epd2, EpDouble *epd3);
+void EpdPow2(int n, EpDouble *epd);
+void EpdPow2Decimal(int n, EpDouble *epd);
+void EpdNormalize(EpDouble *epd);
+void EpdNormalizeDecimal(EpDouble *epd);
+void EpdGetValueAndDecimalExponent(EpDouble *epd, double *value, int *exponent);
+int EpdGetExponent(double value);
+int EpdGetExponentDecimal(double value);
+void EpdMakeInf(EpDouble *epd, int sign);
+void EpdMakeZero(EpDouble *epd, int sign);
+void EpdMakeNan(EpDouble *epd);
+void EpdCopy(EpDouble *from, EpDouble *to);
+int EpdIsInf(EpDouble *epd);
+int EpdIsZero(EpDouble *epd);
+int EpdIsNan(EpDouble *epd);
+int EpdIsNanOrInf(EpDouble *epd);
+int IsInfDouble(double value);
+int IsNanDouble(double value);
+int IsNanOrInfDouble(double value);
+
+#endif /* _EPD */
diff --git a/src/bdd/epd/module.make b/src/bdd/epd/module.make
new file mode 100644
index 00000000..a8084db1
--- /dev/null
+++ b/src/bdd/epd/module.make
@@ -0,0 +1 @@
+SRC += src/bdd/epd/epd.c
diff --git a/src/bdd/mtr/module.make b/src/bdd/mtr/module.make
new file mode 100644
index 00000000..d7fa63d9
--- /dev/null
+++ b/src/bdd/mtr/module.make
@@ -0,0 +1,2 @@
+SRC += src/bdd/mtr/mtrBasic.c \
+ src/bdd/mtr/mtrGroup.c
diff --git a/src/bdd/mtr/mtr.h b/src/bdd/mtr/mtr.h
new file mode 100644
index 00000000..201329ae
--- /dev/null
+++ b/src/bdd/mtr/mtr.h
@@ -0,0 +1,173 @@
+/**CHeaderFile*****************************************************************
+
+ FileName [mtr.h]
+
+ PackageName [mtr]
+
+ Synopsis [Multiway-branch tree manipulation]
+
+ Description [This package provides two layers of functions. Functions
+ of the lower level manipulate multiway-branch trees, implemented
+ according to the classical scheme whereby each node points to its
+ first child and its previous and next siblings. These functions are
+ collected in mtrBasic.c.<p>
+ Functions of the upper layer deal with group trees, that is the trees
+ used by group sifting to represent the grouping of variables. These
+ functions are collected in mtrGroup.c.]
+
+ SeeAlso [The CUDD package documentation; specifically on group
+ sifting.]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+ Revision [$Id: mtr.h,v 1.1.1.1 2003/02/24 22:24:02 wjiang Exp $]
+
+******************************************************************************/
+
+#ifndef __MTR
+#define __MTR
+
+/*---------------------------------------------------------------------------*/
+/* Nested includes */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef SIZEOF_VOID_P
+#define SIZEOF_VOID_P 4
+#endif
+#ifndef SIZEOF_INT
+#define SIZEOF_INT 4
+#endif
+
+#undef CONST
+#if defined(__STDC__) || defined(__cplusplus)
+#define CONST const
+#else /* !(__STDC__ || __cplusplus) */
+#define CONST
+#endif /* !(__STDC__ || __cplusplus) */
+
+/* These are potential duplicates. */
+#ifndef EXTERN
+# ifdef __cplusplus
+# define EXTERN extern "C"
+# else
+# define EXTERN extern
+# endif
+#endif
+#ifndef ARGS
+# if defined(__STDC__) || defined(__cplusplus)
+# define ARGS(protos) protos /* ANSI C */
+# else /* !(__STDC__ || __cplusplus) */
+# define ARGS(protos) () /* K&R C */
+# endif /* !(__STDC__ || __cplusplus) */
+#endif
+
+#if defined(__GNUC__)
+#define MTR_INLINE __inline__
+# if (__GNUC__ >2 || __GNUC_MINOR__ >=7)
+# define MTR_UNUSED __attribute__ ((unused))
+# else
+# define MTR_UNUSED
+# endif
+#else
+#define MTR_INLINE
+#define MTR_UNUSED
+#endif
+
+/* Flag definitions */
+#define MTR_DEFAULT 0x00000000
+#define MTR_TERMINAL 0x00000001
+#define MTR_SOFT 0x00000002
+#define MTR_FIXED 0x00000004
+#define MTR_NEWNODE 0x00000008
+
+/* MTR_MAXHIGH is defined in such a way that on 32-bit and 64-bit
+** machines one can cast a value to (int) without generating a negative
+** number.
+*/
+#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
+#define MTR_MAXHIGH (((MtrHalfWord) ~0) >> 1)
+#else
+#define MTR_MAXHIGH ((MtrHalfWord) ~0)
+#endif
+
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
+typedef unsigned int MtrHalfWord;
+#else
+typedef unsigned short MtrHalfWord;
+#endif
+
+typedef struct MtrNode {
+ MtrHalfWord flags;
+ MtrHalfWord low;
+ MtrHalfWord size;
+ MtrHalfWord index;
+ struct MtrNode *parent;
+ struct MtrNode *child;
+ struct MtrNode *elder;
+ struct MtrNode *younger;
+} MtrNode;
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/* Flag manipulation macros */
+#define MTR_SET(node, flag) (node->flags |= (flag))
+#define MTR_RESET(node, flag) (node->flags &= ~ (flag))
+#define MTR_TEST(node, flag) (node->flags & (flag))
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Function prototypes */
+/*---------------------------------------------------------------------------*/
+
+EXTERN MtrNode * Mtr_AllocNode ARGS(());
+EXTERN void Mtr_DeallocNode ARGS((MtrNode *node));
+EXTERN MtrNode * Mtr_InitTree ARGS(());
+EXTERN void Mtr_FreeTree ARGS((MtrNode *node));
+EXTERN MtrNode * Mtr_CopyTree ARGS((MtrNode *node, int expansion));
+EXTERN void Mtr_MakeFirstChild ARGS((MtrNode *parent, MtrNode *child));
+EXTERN void Mtr_MakeLastChild ARGS((MtrNode *parent, MtrNode *child));
+EXTERN MtrNode * Mtr_CreateFirstChild ARGS((MtrNode *parent));
+EXTERN MtrNode * Mtr_CreateLastChild ARGS((MtrNode *parent));
+EXTERN void Mtr_MakeNextSibling ARGS((MtrNode *first, MtrNode *second));
+EXTERN void Mtr_PrintTree ARGS((MtrNode *node));
+EXTERN MtrNode * Mtr_InitGroupTree ARGS((int lower, int size));
+EXTERN MtrNode * Mtr_MakeGroup ARGS((MtrNode *root, unsigned int low, unsigned int high, unsigned int flags));
+EXTERN MtrNode * Mtr_DissolveGroup ARGS((MtrNode *group));
+EXTERN MtrNode * Mtr_FindGroup ARGS((MtrNode *root, unsigned int low, unsigned int high));
+EXTERN int Mtr_SwapGroups ARGS((MtrNode *first, MtrNode *second));
+EXTERN void Mtr_PrintGroups ARGS((MtrNode *root, int silent));
+EXTERN MtrNode * Mtr_ReadGroups ARGS((FILE *fp, int nleaves));
+
+/**AutomaticEnd***************************************************************/
+
+#endif /* __MTR */
diff --git a/src/bdd/mtr/mtrBasic.c b/src/bdd/mtr/mtrBasic.c
new file mode 100644
index 00000000..2aec8d6b
--- /dev/null
+++ b/src/bdd/mtr/mtrBasic.c
@@ -0,0 +1,426 @@
+/**CFile***********************************************************************
+
+ FileName [mtrBasic.c]
+
+ PackageName [mtr]
+
+ Synopsis [Basic manipulation of multiway branching trees.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Mtr_AllocNode()
+ <li> Mtr_DeallocNode()
+ <li> Mtr_InitTree()
+ <li> Mtr_FreeTree()
+ <li> Mtr_CopyTree()
+ <li> Mtr_MakeFirstChild()
+ <li> Mtr_MakeLastChild()
+ <li> Mtr_CreateFirstChild()
+ <li> Mtr_CreateLastChild()
+ <li> Mtr_MakeNextSibling()
+ <li> Mtr_PrintTree()
+ </ul>
+ ]
+
+ SeeAlso [cudd package]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "mtrInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] MTR_UNUSED = "$Id: mtrBasic.c,v 1.1.1.1 2003/02/24 22:24:02 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Allocates new tree node.]
+
+ Description [Allocates new tree node. Returns pointer to node.]
+
+ SideEffects [None]
+
+ SeeAlso [Mtr_DeallocNode]
+
+******************************************************************************/
+MtrNode *
+Mtr_AllocNode(
+ )
+{
+ MtrNode *node;
+
+ node = ALLOC(MtrNode,1);
+ return node;
+
+} /* Mtr_AllocNode */
+
+
+/**Function********************************************************************
+
+ Synopsis [Deallocates tree node.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Mtr_AllocNode]
+
+******************************************************************************/
+void
+Mtr_DeallocNode(
+ MtrNode * node /* node to be deallocated */)
+{
+ FREE(node);
+ return;
+
+} /* end of Mtr_DeallocNode */
+
+
+/**Function********************************************************************
+
+ Synopsis [Initializes tree with one node.]
+
+ Description [Initializes tree with one node. Returns pointer to node.]
+
+ SideEffects [None]
+
+ SeeAlso [Mtr_FreeTree Mtr_InitGroupTree]
+
+******************************************************************************/
+MtrNode *
+Mtr_InitTree(
+ )
+{
+ MtrNode *node;
+
+ node = Mtr_AllocNode();
+ if (node == NULL) return(NULL);
+
+ node->parent = node->child = node->elder = node->younger = NULL;
+ node->flags = 0;
+
+ return(node);
+
+} /* end of Mtr_InitTree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Disposes of tree rooted at node.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Mtr_InitTree]
+
+******************************************************************************/
+void
+Mtr_FreeTree(
+ MtrNode * node)
+{
+ if (node == NULL) return;
+ if (! MTR_TEST(node,MTR_TERMINAL)) Mtr_FreeTree(node->child);
+ Mtr_FreeTree(node->younger);
+ Mtr_DeallocNode(node);
+ return;
+
+} /* end of Mtr_FreeTree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Makes a copy of tree.]
+
+ Description [Makes a copy of tree. If parameter expansion is greater
+ than 1, it will expand the tree by that factor. It is an error for
+ expansion to be less than 1. Returns a pointer to the copy if
+ successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Mtr_InitTree]
+
+******************************************************************************/
+MtrNode *
+Mtr_CopyTree(
+ MtrNode * node,
+ int expansion)
+{
+ MtrNode *copy;
+
+ if (node == NULL) return(NULL);
+ if (expansion < 1) return(NULL);
+ copy = Mtr_AllocNode();
+ if (copy == NULL) return(NULL);
+ copy->parent = copy->elder = copy->child = copy->younger = NULL;
+ if (node->child != NULL) {
+ copy->child = Mtr_CopyTree(node->child, expansion);
+ if (copy->child == NULL) {
+ Mtr_DeallocNode(copy);
+ return(NULL);
+ }
+ }
+ if (node->younger != NULL) {
+ copy->younger = Mtr_CopyTree(node->younger, expansion);
+ if (copy->younger == NULL) {
+ Mtr_FreeTree(copy);
+ return(NULL);
+ }
+ }
+ copy->flags = node->flags;
+ copy->low = node->low * expansion;
+ copy->size = node->size * expansion;
+ copy->index = node->index * expansion;
+ if (copy->younger) copy->younger->elder = copy;
+ if (copy->child) {
+ MtrNode *auxnode = copy->child;
+ while (auxnode != NULL) {
+ auxnode->parent = copy;
+ auxnode = auxnode->younger;
+ }
+ }
+ return(copy);
+
+} /* end of Mtr_CopyTree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Makes child the first child of parent.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Mtr_MakeLastChild Mtr_CreateFirstChild]
+
+******************************************************************************/
+void
+Mtr_MakeFirstChild(
+ MtrNode * parent,
+ MtrNode * child)
+{
+ child->parent = parent;
+ child->younger = parent->child;
+ child->elder = NULL;
+ if (parent->child != NULL) {
+#ifdef MTR_DEBUG
+ assert(parent->child->elder == NULL);
+#endif
+ parent->child->elder = child;
+ }
+ parent->child = child;
+ return;
+
+} /* end of Mtr_MakeFirstChild */
+
+
+/**Function********************************************************************
+
+ Synopsis [Makes child the last child of parent.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Mtr_MakeFirstChild Mtr_CreateLastChild]
+
+******************************************************************************/
+void
+Mtr_MakeLastChild(
+ MtrNode * parent,
+ MtrNode * child)
+{
+ MtrNode *node;
+
+ child->younger = NULL;
+
+ if (parent->child == NULL) {
+ parent->child = child;
+ child->elder = NULL;
+ } else {
+ for (node = parent->child;
+ node->younger != NULL;
+ node = node->younger);
+ node->younger = child;
+ child->elder = node;
+ }
+ child->parent = parent;
+ return;
+
+} /* end of Mtr_MakeLastChild */
+
+
+/**Function********************************************************************
+
+ Synopsis [Creates a new node and makes it the first child of parent.]
+
+ Description [Creates a new node and makes it the first child of
+ parent. Returns pointer to new child.]
+
+ SideEffects [None]
+
+ SeeAlso [Mtr_MakeFirstChild Mtr_CreateLastChild]
+
+******************************************************************************/
+MtrNode *
+Mtr_CreateFirstChild(
+ MtrNode * parent)
+{
+ MtrNode *child;
+
+ child = Mtr_AllocNode();
+ if (child == NULL) return(NULL);
+
+ child->child = child->younger = child-> elder = NULL;
+ child->flags = 0;
+ Mtr_MakeFirstChild(parent,child);
+ return(child);
+
+} /* end of Mtr_CreateFirstChild */
+
+
+/**Function********************************************************************
+
+ Synopsis [Creates a new node and makes it the last child of parent.]
+
+ Description [Creates a new node and makes it the last child of parent.
+ Returns pointer to new child.]
+
+ SideEffects [None]
+
+ SeeAlso [Mtr_MakeLastChild Mtr_CreateFirstChild]
+
+******************************************************************************/
+MtrNode *
+Mtr_CreateLastChild(
+ MtrNode * parent)
+{
+ MtrNode *child;
+
+ child = Mtr_AllocNode();
+ if (child == NULL) return(NULL);
+
+ child->child = child->younger = child->elder = NULL;
+ child->flags = 0;
+ Mtr_MakeLastChild(parent,child);
+ return(child);
+
+} /* end of Mtr_CreateLastChild */
+
+
+/**Function********************************************************************
+
+ Synopsis [Makes second the next sibling of first.]
+
+ Description [Makes second the next sibling of first. Second becomes a
+ child of the parent of first.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+Mtr_MakeNextSibling(
+ MtrNode * first,
+ MtrNode * second)
+{
+ second->younger = first->younger;
+ if (first->younger != NULL) {
+ first->younger->elder = second;
+ }
+ second->parent = first->parent;
+ first->younger = second;
+ second->elder = first;
+ return;
+
+} /* end of Mtr_MakeNextSibling */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints a tree, one node per line.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso [Mtr_PrintGroups]
+
+******************************************************************************/
+void
+Mtr_PrintTree(
+ MtrNode * node)
+{
+ if (node == NULL) return;
+ (void) fprintf(stdout,
+#if SIZEOF_VOID_P == 8
+ "N=0x%-8lx C=0x%-8lx Y=0x%-8lx E=0x%-8lx P=0x%-8lx F=%x L=%d S=%d\n",
+ (unsigned long) node, (unsigned long) node->child,
+ (unsigned long) node->younger, (unsigned long) node->elder,
+ (unsigned long) node->parent, node->flags, node->low, node->size);
+#else
+ "N=0x%-8x C=0x%-8x Y=0x%-8x E=0x%-8x P=0x%-8x F=%x L=%d S=%d\n",
+ (unsigned) node, (unsigned) node->child,
+ (unsigned) node->younger, (unsigned) node->elder,
+ (unsigned) node->parent, node->flags, node->low, node->size);
+#endif
+ if (!MTR_TEST(node,MTR_TERMINAL)) Mtr_PrintTree(node->child);
+ Mtr_PrintTree(node->younger);
+ return;
+
+} /* end of Mtr_PrintTree */
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
diff --git a/src/bdd/mtr/mtrGroup.c b/src/bdd/mtr/mtrGroup.c
new file mode 100644
index 00000000..ae9c5c2f
--- /dev/null
+++ b/src/bdd/mtr/mtrGroup.c
@@ -0,0 +1,690 @@
+/**CFile***********************************************************************
+
+ FileName [mtrGroup.c]
+
+ PackageName [mtr]
+
+ Synopsis [Functions to support group specification for reordering.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Mtr_InitGroupTree()
+ <li> Mtr_MakeGroup()
+ <li> Mtr_DissolveGroup()
+ <li> Mtr_FindGroup()
+ <li> Mtr_SwapGroups()
+ <li> Mtr_PrintGroups()
+ <li> Mtr_ReadGroups()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> mtrShiftHL
+ </ul>
+ ]
+
+ SeeAlso [cudd package]
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "mtrInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] MTR_UNUSED = "$Id: mtrGroup.c,v 1.1.1.1 2003/02/24 22:24:02 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int mtrShiftHL ARGS((MtrNode *node, int shift));
+
+/**AutomaticEnd***************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Allocate new tree.]
+
+ Description [Allocate new tree with one node, whose low and size
+ fields are specified by the lower and size parameters.
+ Returns pointer to tree root.]
+
+ SideEffects [None]
+
+ SeeAlso [Mtr_InitTree Mtr_FreeTree]
+
+******************************************************************************/
+MtrNode *
+Mtr_InitGroupTree(
+ int lower,
+ int size)
+{
+ MtrNode *root;
+
+ root = Mtr_InitTree();
+ if (root == NULL) return(NULL);
+ root->flags = MTR_DEFAULT;
+ root->low = lower;
+ root->size = size;
+ return(root);
+
+} /* end of Mtr_InitGroupTree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Makes a new group with size leaves starting at low.]
+
+ Description [Makes a new group with size leaves starting at low.
+ If the new group intersects an existing group, it must
+ either contain it or be contained by it. This procedure relies on
+ the low and size fields of each node. It also assumes that the
+ children of each node are sorted in order of increasing low. In
+ case of a valid request, the flags of the new group are set to the
+ value passed in `flags.' This can also be used to change the flags
+ of an existing group. Returns the pointer to the root of the new
+ group upon successful termination; NULL otherwise. If the group
+ already exists, the pointer to its root is returned.]
+
+ SideEffects [None]
+
+ SeeAlso [Mtr_DissolveGroup Mtr_ReadGroups Mtr_FindGroup]
+
+******************************************************************************/
+MtrNode *
+Mtr_MakeGroup(
+ MtrNode * root /* root of the group tree */,
+ unsigned int low /* lower bound of the group */,
+ unsigned int size /* upper bound of the group */,
+ unsigned int flags /* flags for the new group */)
+{
+ MtrNode *node,
+ *first,
+ *last,
+ *previous,
+ *newn;
+
+ /* Sanity check. */
+ if (size == 0)
+ return(NULL);
+
+ /* Check whether current group includes new group. This check is
+ ** necessary at the top-level call. In the subsequent calls it is
+ ** redundant. */
+ if (low < (unsigned int) root->low ||
+ low + size > (unsigned int) (root->low + root->size))
+ return(NULL);
+
+ /* Trying to create an existing group has the effect of updating
+ ** the flags. */
+ if (root->size == size && root->low == low) {
+ root->flags = flags;
+ return(root);
+ }
+
+ /* At this point we know that the new group is properly contained
+ ** in the group of root. We have two possible cases here: - root
+ ** is a terminal node; - root has children. */
+
+ /* Root has no children: create a new group. */
+ if (root->child == NULL) {
+ newn = Mtr_AllocNode();
+ if (newn == NULL) return(NULL); /* out of memory */
+ newn->low = low;
+ newn->size = size;
+ newn->flags = flags;
+ newn->parent = root;
+ newn->elder = newn->younger = newn->child = NULL;
+ root->child = newn;
+ return(newn);
+ }
+
+ /* Root has children: Find all chidren of root that are included
+ ** in the new group. If the group of any child entirely contains
+ ** the new group, call Mtr_MakeGroup recursively. */
+ previous = NULL;
+ first = root->child; /* guaranteed to be non-NULL */
+ while (first != NULL && low >= (unsigned int) (first->low + first->size)) {
+ previous = first;
+ first = first->younger;
+ }
+ if (first == NULL) {
+ /* We have scanned the entire list and we need to append a new
+ ** child at the end of it. Previous points to the last child
+ ** of root. */
+ newn = Mtr_AllocNode();
+ if (newn == NULL) return(NULL); /* out of memory */
+ newn->low = low;
+ newn->size = size;
+ newn->flags = flags;
+ newn->parent = root;
+ newn->elder = previous;
+ previous->younger = newn;
+ newn->younger = newn->child = NULL;
+ return(newn);
+ }
+ /* Here first is non-NULL and low < first->low + first->size. */
+ if (low >= (unsigned int) first->low &&
+ low + size <= (unsigned int) (first->low + first->size)) {
+ /* The new group is contained in the group of first. */
+ newn = Mtr_MakeGroup(first, low, size, flags);
+ return(newn);
+ } else if (low + size <= first->low) {
+ /* The new group is entirely contained in the gap between
+ ** previous and first. */
+ newn = Mtr_AllocNode();
+ if (newn == NULL) return(NULL); /* out of memory */
+ newn->low = low;
+ newn->size = size;
+ newn->flags = flags;
+ newn->child = NULL;
+ newn->parent = root;
+ newn->elder = previous;
+ newn->younger = first;
+ first->elder = newn;
+ if (previous != NULL) {
+ previous->younger = newn;
+ } else {
+ root->child = newn;
+ }
+ return(newn);
+ } else if (low < (unsigned int) first->low &&
+ low + size < (unsigned int) (first->low + first->size)) {
+ /* Trying to cut an existing group: not allowed. */
+ return(NULL);
+ } else if (low > first->low) {
+ /* The new group neither is contained in the group of first
+ ** (this was tested above) nor contains it. It is therefore
+ ** trying to cut an existing group: not allowed. */
+ return(NULL);
+ }
+
+ /* First holds the pointer to the first child contained in the new
+ ** group. Here low <= first->low and low + size >= first->low +
+ ** first->size. One of the two inequalities is strict. */
+ last = first->younger;
+ while (last != NULL &&
+ (unsigned int) (last->low + last->size) < low + size) {
+ last = last->younger;
+ }
+ if (last == NULL) {
+ /* All the chilren of root from first onward become children
+ ** of the new group. */
+ newn = Mtr_AllocNode();
+ if (newn == NULL) return(NULL); /* out of memory */
+ newn->low = low;
+ newn->size = size;
+ newn->flags = flags;
+ newn->child = first;
+ newn->parent = root;
+ newn->elder = previous;
+ newn->younger = NULL;
+ first->elder = NULL;
+ if (previous != NULL) {
+ previous->younger = newn;
+ } else {
+ root->child = newn;
+ }
+ last = first;
+ while (last != NULL) {
+ last->parent = newn;
+ last = last->younger;
+ }
+ return(newn);
+ }
+
+ /* Here last != NULL and low + size <= last->low + last->size. */
+ if (low + size - 1 >= (unsigned int) last->low &&
+ low + size < (unsigned int) (last->low + last->size)) {
+ /* Trying to cut an existing group: not allowed. */
+ return(NULL);
+ }
+
+ /* First and last point to the first and last of the children of
+ ** root that are included in the new group. Allocate a new node
+ ** and make all children of root between first and last chidren of
+ ** the new node. Previous points to the child of root immediately
+ ** preceeding first. If it is NULL, then first is the first child
+ ** of root. */
+ newn = Mtr_AllocNode();
+ if (newn == NULL) return(NULL); /* out of memory */
+ newn->low = low;
+ newn->size = size;
+ newn->flags = flags;
+ newn->child = first;
+ newn->parent = root;
+ if (previous == NULL) {
+ root->child = newn;
+ } else {
+ previous->younger = newn;
+ }
+ newn->elder = previous;
+ newn->younger = last->younger;
+ if (last->younger != NULL) {
+ last->younger->elder = newn;
+ }
+ last->younger = NULL;
+ first->elder = NULL;
+ for (node = first; node != NULL; node = node->younger) {
+ node->parent = newn;
+ }
+
+ return(newn);
+
+} /* end of Mtr_MakeGroup */
+
+
+/**Function********************************************************************
+
+ Synopsis [Merges the children of `group' with the children of its
+ parent.]
+
+ Description [Merges the children of `group' with the children of its
+ parent. Disposes of the node pointed by group. If group is the
+ root of the group tree, this procedure leaves the tree unchanged.
+ Returns the pointer to the parent of `group' upon successful
+ termination; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Mtr_MakeGroup]
+
+******************************************************************************/
+MtrNode *
+Mtr_DissolveGroup(
+ MtrNode * group /* group to be dissolved */)
+{
+ MtrNode *parent;
+ MtrNode *last;
+
+ parent = group->parent;
+
+ if (parent == NULL) return(NULL);
+ if (MTR_TEST(group,MTR_TERMINAL) || group->child == NULL) return(NULL);
+
+ /* Make all children of group children of its parent, and make
+ ** last point to the last child of group. */
+ for (last = group->child; last->younger != NULL; last = last->younger) {
+ last->parent = parent;
+ }
+ last->parent = parent;
+
+ last->younger = group->younger;
+ if (group->younger != NULL) {
+ group->younger->elder = last;
+ }
+
+ group->child->elder = group->elder;
+ if (group == parent->child) {
+ parent->child = group->child;
+ } else {
+ group->elder->younger = group->child;
+ }
+
+ Mtr_DeallocNode(group);
+ return(parent);
+
+} /* end of Mtr_DissolveGroup */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds a group with size leaves starting at low, if it exists.]
+
+ Description [Finds a group with size leaves starting at low, if it
+ exists. This procedure relies on the low and size fields of each
+ node. It also assumes that the children of each node are sorted in
+ order of increasing low. Returns the pointer to the root of the
+ group upon successful termination; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+MtrNode *
+Mtr_FindGroup(
+ MtrNode * root /* root of the group tree */,
+ unsigned int low /* lower bound of the group */,
+ unsigned int size /* upper bound of the group */)
+{
+ MtrNode *node;
+
+#ifdef MTR_DEBUG
+ /* We cannot have a non-empty proper subgroup of a singleton set. */
+ assert(!MTR_TEST(root,MTR_TERMINAL));
+#endif
+
+ /* Sanity check. */
+ if (size < 1) return(NULL);
+
+ /* Check whether current group includes the group sought. This
+ ** check is necessary at the top-level call. In the subsequent
+ ** calls it is redundant. */
+ if (low < (unsigned int) root->low ||
+ low + size > (unsigned int) (root->low + root->size))
+ return(NULL);
+
+ if (root->size == size && root->low == low)
+ return(root);
+
+ if (root->child == NULL)
+ return(NULL);
+
+ /* Find all chidren of root that are included in the new group. If
+ ** the group of any child entirely contains the new group, call
+ ** Mtr_MakeGroup recursively. */
+ node = root->child;
+ while (low >= (unsigned int) (node->low + node->size)) {
+ node = node->younger;
+ }
+ if (low + size <= (unsigned int) (node->low + node->size)) {
+ /* The group is contained in the group of node. */
+ node = Mtr_FindGroup(node, low, size);
+ return(node);
+ } else {
+ return(NULL);
+ }
+
+} /* end of Mtr_FindGroup */
+
+
+/**Function********************************************************************
+
+ Synopsis [Swaps two children of a tree node.]
+
+ Description [Swaps two children of a tree node. Adjusts the high and
+ low fields of the two nodes and their descendants. The two children
+ must be adjacent. However, first may be the younger sibling of second.
+ Returns 1 in case of success; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+Mtr_SwapGroups(
+ MtrNode * first /* first node to be swapped */,
+ MtrNode * second /* second node to be swapped */)
+{
+ MtrNode *node;
+ MtrNode *parent;
+ int sizeFirst;
+ int sizeSecond;
+
+ if (second->younger == first) { /* make first first */
+ node = first;
+ first = second;
+ second = node;
+ } else if (first->younger != second) { /* non-adjacent */
+ return(0);
+ }
+
+ sizeFirst = first->size;
+ sizeSecond = second->size;
+
+ /* Swap the two nodes. */
+ parent = first->parent;
+ if (parent == NULL || second->parent != parent) return(0);
+ if (parent->child == first) {
+ parent->child = second;
+ } else { /* first->elder != NULL */
+ first->elder->younger = second;
+ }
+ if (second->younger != NULL) {
+ second->younger->elder = first;
+ }
+ first->younger = second->younger;
+ second->elder = first->elder;
+ first->elder = second;
+ second->younger = first;
+
+ /* Adjust the high and low fields. */
+ if (!mtrShiftHL(first,sizeSecond)) return(0);
+ if (!mtrShiftHL(second,-sizeFirst)) return(0);
+
+ return(1);
+
+} /* end of Mtr_SwapGroups */
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints the groups as a parenthesized list.]
+
+ Description [Prints the groups as a parenthesized list. After each
+ group, the group's flag are printed, preceded by a `|'. For each
+ flag (except MTR_TERMINAL) a character is printed.
+ <ul>
+ <li>F: MTR_FIXED
+ <li>N: MTR_NEWNODE
+ <li>S: MTR_SOFT
+ </ul>
+ The second argument, silent, if different from 0, causes
+ Mtr_PrintGroups to only check the syntax of the group tree.
+ ]
+
+ SideEffects [None]
+
+ SeeAlso [Mtr_PrintTree]
+
+******************************************************************************/
+void
+Mtr_PrintGroups(
+ MtrNode * root /* root of the group tree */,
+ int silent /* flag to check tree syntax only */)
+{
+ MtrNode *node;
+
+ assert(root != NULL);
+ assert(root->younger == NULL || root->younger->elder == root);
+ assert(root->elder == NULL || root->elder->younger == root);
+ if (!silent) (void) printf("(%d",root->low);
+ if (MTR_TEST(root,MTR_TERMINAL) || root->child == NULL) {
+ if (!silent) (void) printf(",");
+ } else {
+ node = root->child;
+ while (node != NULL) {
+ assert(node->low >= root->low && (int) (node->low + node->size) <= (int) (root->low + root->size));
+ assert(node->parent == root);
+ Mtr_PrintGroups(node,silent);
+ node = node->younger;
+ }
+ }
+ if (!silent) {
+ (void) printf("%d", root->low + root->size - 1);
+ if (root->flags != MTR_DEFAULT) {
+ (void) printf("|");
+ if (MTR_TEST(root,MTR_FIXED)) (void) printf("F");
+ if (MTR_TEST(root,MTR_NEWNODE)) (void) printf("N");
+ if (MTR_TEST(root,MTR_SOFT)) (void) printf("S");
+ }
+ (void) printf(")");
+ if (root->parent == NULL) (void) printf("\n");
+ }
+ assert((root->flags &~(MTR_TERMINAL | MTR_SOFT | MTR_FIXED | MTR_NEWNODE)) == 0);
+ return;
+
+} /* end of Mtr_PrintGroups */
+
+
+/**Function********************************************************************
+
+ Synopsis [Reads groups from a file and creates a group tree.]
+
+ Description [Reads groups from a file and creates a group tree.
+ Each group is specified by three fields:
+ <xmp>
+ low size flags.
+ </xmp>
+ Low and size are (short) integers. Flags is a string composed of the
+ following characters (with associated translation):
+ <ul>
+ <li>D: MTR_DEFAULT
+ <li>F: MTR_FIXED
+ <li>N: MTR_NEWNODE
+ <li>S: MTR_SOFT
+ <li>T: MTR_TERMINAL
+ </ul>
+ Normally, the only flags that are needed are D and F. Groups and
+ fields are separated by white space (spaces, tabs, and newlines).
+ Returns a pointer to the group tree if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Mtr_InitGroupTree Mtr_MakeGroup]
+
+******************************************************************************/
+MtrNode *
+Mtr_ReadGroups(
+ FILE * fp /* file pointer */,
+ int nleaves /* number of leaves of the new tree */)
+{
+ int low;
+ int size;
+ int err;
+ unsigned int flags;
+ MtrNode *root;
+ MtrNode *node;
+ char attrib[8*sizeof(unsigned int)+1];
+ char *c;
+
+ root = Mtr_InitGroupTree(0,nleaves);
+ if (root == NULL) return NULL;
+
+ while (! feof(fp)) {
+ /* Read a triple and check for consistency. */
+ err = fscanf(fp, "%d %d %s", &low, &size, attrib);
+ if (err == EOF) {
+ break;
+ } else if (err != 3) {
+ return(NULL);
+ } else if (low < 0 || low+size > nleaves || size < 1) {
+ return(NULL);
+ } else if (strlen(attrib) > 8 * sizeof(MtrHalfWord)) {
+ /* Not enough bits in the flags word to store these many
+ ** attributes. */
+ return(NULL);
+ }
+
+ /* Parse the flag string. Currently all flags are permitted,
+ ** to make debugging easier. Normally, specifying NEWNODE
+ ** wouldn't be allowed. */
+ flags = MTR_DEFAULT;
+ for (c=attrib; *c != 0; c++) {
+ switch (*c) {
+ case 'D':
+ break;
+ case 'F':
+ flags |= MTR_FIXED;
+ break;
+ case 'N':
+ flags |= MTR_NEWNODE;
+ break;
+ case 'S':
+ flags |= MTR_SOFT;
+ break;
+ case 'T':
+ flags |= MTR_TERMINAL;
+ break;
+ default:
+ return NULL;
+ }
+ }
+ node = Mtr_MakeGroup(root, (MtrHalfWord) low, (MtrHalfWord) size,
+ flags);
+ if (node == NULL) return(NULL);
+ }
+
+ return(root);
+
+} /* end of Mtr_ReadGroups */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Adjusts the low fields of a node and its descendants.]
+
+ Description [Adjusts the low fields of a node and its
+ descendants. Adds shift to low of each node. Checks that no
+ out-of-bounds values result. Returns 1 in case of success; 0
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+mtrShiftHL(
+ MtrNode * node /* group tree node */,
+ int shift /* amount by which low should be changed */)
+{
+ MtrNode *auxnode;
+ int low;
+
+ low = (int) node->low;
+
+
+ low += shift;
+
+ if (low < 0 || low + (int) (node->size - 1) > (int) MTR_MAXHIGH) return(0);
+
+ node->low = (MtrHalfWord) low;
+
+ if (!MTR_TEST(node,MTR_TERMINAL) && node->child != NULL) {
+ auxnode = node->child;
+ do {
+ if (!mtrShiftHL(auxnode,shift)) return(0);
+ auxnode = auxnode->younger;
+ } while (auxnode != NULL);
+ }
+
+ return(1);
+
+} /* end of mtrShiftHL */
+
diff --git a/src/bdd/mtr/mtrInt.h b/src/bdd/mtr/mtrInt.h
new file mode 100644
index 00000000..a8d5aa6c
--- /dev/null
+++ b/src/bdd/mtr/mtrInt.h
@@ -0,0 +1,65 @@
+/**CHeaderFile*****************************************************************
+
+ FileName [mtrInt.h]
+
+ PackageName [mtr]
+
+ Synopsis [Internal data structures of the mtr package]
+
+ Description [In this package all definitions are external.]
+
+ SeeAlso []
+
+ Author [Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+ Revision [$Id: mtrInt.h,v 1.1.1.1 2003/02/24 22:24:02 wjiang Exp $]
+
+******************************************************************************/
+
+#ifndef _MTRINT
+#define _MTRINT
+
+#include "mtr.h"
+
+/*---------------------------------------------------------------------------*/
+/* Nested includes */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Function prototypes */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticEnd***************************************************************/
+
+#endif /* _MTRINT */
diff --git a/src/bdd/parse/module.make b/src/bdd/parse/module.make
new file mode 100644
index 00000000..ea535e6e
--- /dev/null
+++ b/src/bdd/parse/module.make
@@ -0,0 +1,2 @@
+SRC += src/bdd/parse/parseCore.c \
+ src/bdd/parse/parseStack.c
diff --git a/src/bdd/parse/parse.h b/src/bdd/parse/parse.h
new file mode 100644
index 00000000..8364e782
--- /dev/null
+++ b/src/bdd/parse/parse.h
@@ -0,0 +1,53 @@
+/**CFile****************************************************************
+
+ FileName [parse.h]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis [Parsing symbolic Boolean formulas into BDDs.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - September 8, 2003.]
+
+ Revision [$Id: parse.h,v 1.0 2003/09/08 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __PARSE_H__
+#define __PARSE_H__
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// STRUCTURE DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// GLOBAL VARIABLES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*=== parseCore.c =============================================================*/
+extern DdNode * Parse_FormulaParser( FILE * pOutput, char * pFormula, int nVars, int nRanks,
+ char * ppVarNames[], DdManager * dd, DdNode * pbVars[] );
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+#endif
diff --git a/src/bdd/parse/parseCore.c b/src/bdd/parse/parseCore.c
new file mode 100644
index 00000000..d60687a3
--- /dev/null
+++ b/src/bdd/parse/parseCore.c
@@ -0,0 +1,504 @@
+/**CFile****************************************************************
+
+ FileNameIn [parseCore.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Boolean formula parser.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - February 1, 2003.]
+
+ Revision [$Id: parseCore.c,v 1.0 2003/02/01 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+/*
+ Some aspects of Boolean Formula Parser:
+
+ 1) The names in the boolean formulas can be any strings of symbols
+ that start with char or underscore and contain chars, digits
+ and underscores: For example: 1) a&b <+> c'&d => a + b;
+ 2) a1 b2 c3' dummy' + (a2+b2')c3 dummy
+ 2) Constant values 0 and 1 can be used just like normal variables
+ 3) Any boolean operator (listed below) and parantheses can be used
+ any number of times provided there are equal number of opening
+ and closing parantheses.
+ 4) By default, absence of an operator between vars and before and
+ after parantheses is taken for AND.
+ 5) Both complementation prefix and complementation suffix can be
+ used at the same time (but who needs this?)
+ 6) Spaces (tabs, end-of-lines) may be inserted anywhere,
+ except between characters of the operations: <=>, =>, <=, <+>
+ 7) The stack size is defined by macro STACKSIZE and is used by the
+ stack constructor.
+*/
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+#include "parseInt.h"
+
+// the list of operation symbols to be used in expressions
+#define PARSE_SYM_OPEN '(' // opening paranthesis
+#define PARSE_SYM_CLOSE ')' // closing paranthesis
+#define PARSE_SYM_LOWER '[' // shifts one rank down
+#define PARSE_SYM_RAISE ']' // shifts one rank up
+#define PARSE_SYM_CONST0 '0' // constant 0
+#define PARSE_SYM_CONST1 '1' // constant 1
+#define PARSE_SYM_NEGBEF1 '!' // negation before the variable
+#define PARSE_SYM_NEGBEF2 '~' // negation before the variable
+#define PARSE_SYM_NEGAFT '\'' // negation after the variable
+#define PARSE_SYM_AND1 '&' // logic AND
+#define PARSE_SYM_AND2 '*' // logic AND
+#define PARSE_SYM_XOR1 '<' // logic EXOR (the 1st symbol)
+#define PARSE_SYM_XOR2 '+' // logic EXOR (the 2nd symbol)
+#define PARSE_SYM_XOR3 '>' // logic EXOR (the 3rd symbol)
+#define PARSE_SYM_OR '+' // logic OR
+#define PARSE_SYM_EQU1 '<' // equvalence (the 1st symbol)
+#define PARSE_SYM_EQU2 '=' // equvalence (the 2nd symbol)
+#define PARSE_SYM_EQU3 '>' // equvalence (the 3rd symbol)
+#define PARSE_SYM_FLR1 '=' // implication (the 1st symbol)
+#define PARSE_SYM_FLR2 '>' // implication (the 2nd symbol)
+#define PARSE_SYM_FLL1 '<' // backward imp (the 1st symbol)
+#define PARSE_SYM_FLL2 '=' // backward imp (the 2nd symbol)
+// PARSE_SYM_FLR1 and PARSE_SYM_FLR2 should be the same as PARSE_SYM_EQU2 and PARSE_SYM_EQU3!
+
+// the list of opcodes (also specifying operation precedence)
+#define PARSE_OPER_NEG 10 // negation
+#define PARSE_OPER_AND 9 // logic AND
+#define PARSE_OPER_XOR 8 // logic EXOR (a'b | ab')
+#define PARSE_OPER_OR 7 // logic OR
+#define PARSE_OPER_EQU 6 // equvalence (a'b'| ab )
+#define PARSE_OPER_FLR 5 // implication ( a' | b )
+#define PARSE_OPER_FLL 4 // backward imp ( 'b | a )
+#define PARSE_OPER_MARK 1 // OpStack token standing for an opening paranthesis
+
+// these are values of the internal Flag
+#define PARSE_FLAG_START 1 // after the opening parenthesis
+#define PARSE_FLAG_VAR 2 // after operation is received
+#define PARSE_FLAG_OPER 3 // after operation symbol is received
+#define PARSE_FLAG_ERROR 4 // when error is detected
+
+#define STACKSIZE 1000
+
+static DdNode * Parse_ParserPerformTopOp( DdManager * dd, Parse_StackFn_t * pStackFn, int Oper );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Derives the BDD corresponding to the formula in language L.]
+
+ Description [Takes the stream to output messages, the formula, the number
+ variables and the rank in the formula. The array of variable names is also
+ given. The BDD manager and the elementary 0-rank variable are the last two
+ arguments. The manager should have at least as many variables as
+ nVars * (nRanks + 1). The 0-rank variables should have numbers larger
+ than the variables of other ranks.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdNode * Parse_FormulaParser( FILE * pOutput, char * pFormulaInit, int nVars, int nRanks,
+ char * ppVarNames[], DdManager * dd, DdNode * pbVars[] )
+{
+ char * pFormula;
+ Parse_StackFn_t * pStackFn;
+ Parse_StackOp_t * pStackOp;
+ DdNode * bFunc, * bTemp;
+ char * pTemp;
+ int nParans, fFound, Flag;
+ int Oper, Oper1, Oper2;
+ int i, v, fLower;
+
+ // make sure that the number of vars and ranks is correct
+ if ( nVars * (nRanks + 1) > dd->size )
+ {
+ printf( "Parse_FormulaParser(): The BDD manager does not have enough variables.\n" );
+ return NULL;
+ }
+
+ // make sure that the number of opening and closing parantheses is the same
+ nParans = 0;
+ for ( pTemp = pFormulaInit; *pTemp; pTemp++ )
+ if ( *pTemp == '(' )
+ nParans++;
+ else if ( *pTemp == ')' )
+ nParans--;
+ if ( nParans != 0 )
+ {
+ fprintf( pOutput, "Parse_FormulaParser(): Different number of opening and closing parantheses ().\n" );
+ return NULL;
+ }
+
+ nParans = 0;
+ for ( pTemp = pFormulaInit; *pTemp; pTemp++ )
+ if ( *pTemp == '[' )
+ nParans++;
+ else if ( *pTemp == ']' )
+ nParans--;
+ if ( nParans != 0 )
+ {
+ fprintf( pOutput, "Parse_FormulaParser(): Different number of opening and closing brackets [].\n" );
+ return NULL;
+ }
+
+ // copy the formula
+ pFormula = ALLOC( char, strlen(pFormulaInit) + 3 );
+ sprintf( pFormula, "(%s)", pFormulaInit );
+
+ // start the stacks
+ pStackFn = Parse_StackFnStart( STACKSIZE );
+ pStackOp = Parse_StackOpStart( STACKSIZE );
+
+ Flag = PARSE_FLAG_START;
+ fLower = 0;
+ for ( pTemp = pFormula; *pTemp; pTemp++ )
+ {
+ switch ( *pTemp )
+ {
+ // skip all spaces, tabs, and end-of-lines
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ continue;
+
+ // treat Constant 0 as a variable
+ case PARSE_SYM_CONST0:
+ Parse_StackFnPush( pStackFn, b0 ); Cudd_Ref( b0 );
+ if ( Flag == PARSE_FLAG_VAR )
+ {
+ fprintf( pOutput, "Parse_FormulaParser(): No operation symbol before constant 0.\n" );
+ Flag = PARSE_FLAG_ERROR;
+ break;
+ }
+ Flag = PARSE_FLAG_VAR;
+ break;
+
+ // the same for Constant 1
+ case PARSE_SYM_CONST1:
+ Parse_StackFnPush( pStackFn, b1 ); Cudd_Ref( b1 );
+ if ( Flag == PARSE_FLAG_VAR )
+ {
+ fprintf( pOutput, "Parse_FormulaParser(): No operation symbol before constant 1.\n" );
+ Flag = PARSE_FLAG_ERROR;
+ break;
+ }
+ Flag = PARSE_FLAG_VAR;
+ break;
+
+ case PARSE_SYM_NEGBEF1:
+ case PARSE_SYM_NEGBEF2:
+ if ( Flag == PARSE_FLAG_VAR )
+ {// if NEGBEF follows a variable, AND is assumed
+ Parse_StackOpPush( pStackOp, PARSE_OPER_AND );
+ Flag = PARSE_FLAG_OPER;
+ }
+ Parse_StackOpPush( pStackOp, PARSE_OPER_NEG );
+ break;
+
+ case PARSE_SYM_NEGAFT:
+ if ( Flag != PARSE_FLAG_VAR )
+ {// if there is no variable before NEGAFT, it is an error
+ fprintf( pOutput, "Parse_FormulaParser(): No variable is specified before the negation suffix.\n" );
+ Flag = PARSE_FLAG_ERROR;
+ break;
+ }
+ else // if ( Flag == PARSE_FLAG_VAR )
+ Parse_StackFnPush( pStackFn, Cudd_Not( Parse_StackFnPop(pStackFn) ) );
+ break;
+
+ case PARSE_SYM_AND1:
+ case PARSE_SYM_AND2:
+ case PARSE_SYM_OR:
+ if ( Flag != PARSE_FLAG_VAR )
+ {
+ fprintf( pOutput, "Parse_FormulaParser(): There is no variable before AND, EXOR, or OR.\n" );
+ Flag = PARSE_FLAG_ERROR;
+ break;
+ }
+ if ( *pTemp == PARSE_SYM_AND1 || *pTemp == PARSE_SYM_AND2 )
+ Parse_StackOpPush( pStackOp, PARSE_OPER_AND );
+ else //if ( Str[Pos] == PARSE_SYM_OR )
+ Parse_StackOpPush( pStackOp, PARSE_OPER_OR );
+ Flag = PARSE_FLAG_OPER;
+ break;
+
+ case PARSE_SYM_EQU1:
+ if ( Flag != PARSE_FLAG_VAR )
+ {
+ fprintf( pOutput, "Parse_FormulaParser(): There is no variable before Equivalence or Implication\n" );
+ Flag = PARSE_FLAG_ERROR; break;
+ }
+ if ( pTemp[1] == PARSE_SYM_EQU2 )
+ { // check what is the next symbol in the string
+ pTemp++;
+ if ( pTemp[1] == PARSE_SYM_EQU3 )
+ {
+ pTemp++;
+ Parse_StackOpPush( pStackOp, PARSE_OPER_EQU );
+ }
+ else
+ {
+ Parse_StackOpPush( pStackOp, PARSE_OPER_FLL );
+ }
+ }
+ else if ( pTemp[1] == PARSE_SYM_XOR2 )
+ {
+ pTemp++;
+ if ( pTemp[1] == PARSE_SYM_XOR3 )
+ {
+ pTemp++;
+ Parse_StackOpPush( pStackOp, PARSE_OPER_XOR );
+ }
+ else
+ {
+ fprintf( pOutput, "Parse_FormulaParser(): Wrong symbol after \"%c%c\"\n", PARSE_SYM_EQU1, PARSE_SYM_XOR2 );
+ Flag = PARSE_FLAG_ERROR;
+ break;
+ }
+ }
+ else
+ {
+ fprintf( pOutput, "Parse_FormulaParser(): Wrong symbol after \"%c\"\n", PARSE_SYM_EQU1 );
+ Flag = PARSE_FLAG_ERROR;
+ break;
+ }
+ Flag = PARSE_FLAG_OPER;
+ break;
+
+ case PARSE_SYM_EQU2:
+ if ( Flag != PARSE_FLAG_VAR )
+ {
+ fprintf( pOutput, "Parse_FormulaParser(): There is no variable before Reverse Implication\n" );
+ Flag = PARSE_FLAG_ERROR;
+ break;
+ }
+ if ( pTemp[1] == PARSE_SYM_EQU3 )
+ {
+ pTemp++;
+ Parse_StackOpPush( pStackOp, PARSE_OPER_FLR );
+ }
+ else
+ {
+ fprintf( pOutput, "Parse_FormulaParser(): Wrong symbol after \"%c\"\n", PARSE_SYM_EQU2 );
+ Flag = PARSE_FLAG_ERROR;
+ break;
+ }
+ Flag = PARSE_FLAG_OPER;
+ break;
+
+ case PARSE_SYM_LOWER:
+ case PARSE_SYM_OPEN:
+ if ( Flag == PARSE_FLAG_VAR )
+ Parse_StackOpPush( pStackOp, PARSE_OPER_AND );
+ Parse_StackOpPush( pStackOp, PARSE_OPER_MARK );
+ // after an opening bracket, it feels like starting over again
+ Flag = PARSE_FLAG_START;
+ break;
+
+ case PARSE_SYM_RAISE:
+ fLower = 1;
+ case PARSE_SYM_CLOSE:
+ if ( !Parse_StackOpIsEmpty( pStackOp ) )
+ {
+ while ( 1 )
+ {
+ if ( Parse_StackOpIsEmpty( pStackOp ) )
+ {
+ fprintf( pOutput, "Parse_FormulaParser(): There is no opening paranthesis\n" );
+ Flag = PARSE_FLAG_ERROR;
+ break;
+ }
+ Oper = Parse_StackOpPop( pStackOp );
+ if ( Oper == PARSE_OPER_MARK )
+ break;
+
+ // perform the given operation
+ if ( Parse_ParserPerformTopOp( dd, pStackFn, Oper ) == NULL )
+ {
+ fprintf( pOutput, "Parse_FormulaParser(): Unknown operation\n" );
+ free( pFormula );
+ return NULL;
+ }
+ }
+
+ if ( fLower )
+ {
+ bFunc = Parse_StackFnPop( pStackFn );
+ bFunc = Extra_bddMove( dd, bTemp = bFunc, -nVars ); Cudd_Ref( bFunc );
+ Cudd_RecursiveDeref( dd, bTemp );
+ Parse_StackFnPush( pStackFn, bFunc );
+ }
+ }
+ else
+ {
+ fprintf( pOutput, "Parse_FormulaParser(): There is no opening paranthesis\n" );
+ Flag = PARSE_FLAG_ERROR;
+ break;
+ }
+ if ( Flag != PARSE_FLAG_ERROR )
+ Flag = PARSE_FLAG_VAR;
+ fLower = 0;
+ break;
+
+
+ default:
+ // scan the next name
+ fFound = 0;
+ for ( i = 0; pTemp[i] && pTemp[i] != ' ' && pTemp[i] != '\t' && pTemp[i] != '\r' && pTemp[i] != '\n'; i++ )
+ {
+ for ( v = 0; v < nVars; v++ )
+ if ( strncmp( pTemp, ppVarNames[v], i+1 ) == 0 && strlen(ppVarNames[v]) == (unsigned)(i+1) )
+ {
+ pTemp += i;
+ fFound = 1;
+ break;
+ }
+ if ( fFound )
+ break;
+ }
+ if ( !fFound )
+ {
+ fprintf( pOutput, "Parse_FormulaParser(): The parser cannot find var \"%s\" in the input var list.\n", pTemp );
+ Flag = PARSE_FLAG_ERROR;
+ break;
+ }
+
+ // assume operation AND, if vars follow one another
+ if ( Flag == PARSE_FLAG_VAR )
+ Parse_StackOpPush( pStackOp, PARSE_OPER_AND );
+ Parse_StackFnPush( pStackFn, pbVars[v] ); Cudd_Ref( pbVars[v] );
+ Flag = PARSE_FLAG_VAR;
+ break;
+ }
+
+ if ( Flag == PARSE_FLAG_ERROR )
+ break; // error exit
+ else if ( Flag == PARSE_FLAG_START )
+ continue; // go on parsing
+ else if ( Flag == PARSE_FLAG_VAR )
+ while ( 1 )
+ { // check if there are negations in the OpStack
+ if ( Parse_StackOpIsEmpty(pStackOp) )
+ break;
+ Oper = Parse_StackOpPop( pStackOp );
+ if ( Oper != PARSE_OPER_NEG )
+ {
+ Parse_StackOpPush( pStackOp, Oper );
+ break;
+ }
+ else
+ {
+ Parse_StackFnPush( pStackFn, Cudd_Not(Parse_StackFnPop(pStackFn)) );
+ }
+ }
+ else // if ( Flag == PARSE_FLAG_OPER )
+ while ( 1 )
+ { // execute all the operations in the OpStack
+ // with precedence higher or equal than the last one
+ Oper1 = Parse_StackOpPop( pStackOp ); // the last operation
+ if ( Parse_StackOpIsEmpty(pStackOp) )
+ { // if it is the only operation, push it back
+ Parse_StackOpPush( pStackOp, Oper1 );
+ break;
+ }
+ Oper2 = Parse_StackOpPop( pStackOp ); // the operation before the last one
+ if ( Oper2 >= Oper1 )
+ { // if Oper2 precedence is higher or equal, execute it
+// Parse_StackPush( pStackFn, Operation( FunStack.Pop(), FunStack.Pop(), Oper2 ) );
+ if ( Parse_ParserPerformTopOp( dd, pStackFn, Oper2 ) == NULL )
+ {
+ fprintf( pOutput, "Parse_FormulaParser(): Unknown operation\n" );
+ free( pFormula );
+ return NULL;
+ }
+ Parse_StackOpPush( pStackOp, Oper1 ); // push the last operation back
+ }
+ else
+ { // if Oper2 precedence is lower, push them back and done
+ Parse_StackOpPush( pStackOp, Oper2 );
+ Parse_StackOpPush( pStackOp, Oper1 );
+ break;
+ }
+ }
+ }
+
+ if ( Flag != PARSE_FLAG_ERROR )
+ {
+ if ( !Parse_StackFnIsEmpty(pStackFn) )
+ {
+ bFunc = Parse_StackFnPop(pStackFn);
+ if ( Parse_StackFnIsEmpty(pStackFn) )
+ if ( Parse_StackOpIsEmpty(pStackOp) )
+ {
+ Parse_StackFnFree(pStackFn);
+ Parse_StackOpFree(pStackOp);
+ Cudd_Deref( bFunc );
+ free( pFormula );
+ return bFunc;
+ }
+ else
+ fprintf( pOutput, "Parse_FormulaParser(): Something is left in the operation stack\n" );
+ else
+ fprintf( pOutput, "Parse_FormulaParser(): Something is left in the function stack\n" );
+ }
+ else
+ fprintf( pOutput, "Parse_FormulaParser(): The input string is empty\n" );
+ }
+ free( pFormula );
+ return NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs the operation on the top entries in the stack.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdNode * Parse_ParserPerformTopOp( DdManager * dd, Parse_StackFn_t * pStackFn, int Oper )
+{
+ DdNode * bArg1, * bArg2, * bFunc;
+ // perform the given operation
+ bArg2 = Parse_StackFnPop( pStackFn );
+ bArg1 = Parse_StackFnPop( pStackFn );
+ if ( Oper == PARSE_OPER_AND )
+ bFunc = Cudd_bddAnd( dd, bArg1, bArg2 );
+ else if ( Oper == PARSE_OPER_XOR )
+ bFunc = Cudd_bddXor( dd, bArg1, bArg2 );
+ else if ( Oper == PARSE_OPER_OR )
+ bFunc = Cudd_bddOr( dd, bArg1, bArg2 );
+ else if ( Oper == PARSE_OPER_EQU )
+ bFunc = Cudd_bddXnor( dd, bArg1, bArg2 );
+ else if ( Oper == PARSE_OPER_FLR )
+ bFunc = Cudd_bddOr( dd, Cudd_Not(bArg1), bArg2 );
+ else if ( Oper == PARSE_OPER_FLL )
+ bFunc = Cudd_bddOr( dd, Cudd_Not(bArg2), bArg1 );
+ else
+ return NULL;
+ Cudd_Ref( bFunc );
+ Cudd_RecursiveDeref( dd, bArg1 );
+ Cudd_RecursiveDeref( dd, bArg2 );
+ Parse_StackFnPush( pStackFn, bFunc );
+ return bFunc;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
diff --git a/src/bdd/parse/parseInt.h b/src/bdd/parse/parseInt.h
new file mode 100644
index 00000000..6e6c49b0
--- /dev/null
+++ b/src/bdd/parse/parseInt.h
@@ -0,0 +1,73 @@
+/**CFile****************************************************************
+
+ FileName [parseInt.h]
+
+ PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]
+
+ Synopsis [Parsing symbolic Boolean formulas into BDDs.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - September 8, 2003.]
+
+ Revision [$Id: parseInt.h,v 1.0 2003/09/08 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __PARSE_INT_H__
+#define __PARSE_INT_H__
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+
+#include <stdio.h>
+#include "cuddInt.h"
+#include "extra.h"
+#include "parse.h"
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// STRUCTURE DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+typedef int bool;
+
+typedef struct ParseStackFnStruct Parse_StackFn_t; // the function stack
+typedef struct ParseStackOpStruct Parse_StackOp_t; // the operation stack
+
+////////////////////////////////////////////////////////////////////////
+/// GLOBAL VARIABLES ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*=== parseStack.c =============================================================*/
+extern Parse_StackFn_t * Parse_StackFnStart ( int nDepth );
+extern bool Parse_StackFnIsEmpty( Parse_StackFn_t * p );
+extern void Parse_StackFnPush ( Parse_StackFn_t * p, DdNode * bFunc );
+extern DdNode * Parse_StackFnPop ( Parse_StackFn_t * p );
+extern void Parse_StackFnFree ( Parse_StackFn_t * p );
+
+extern Parse_StackOp_t * Parse_StackOpStart ( int nDepth );
+extern bool Parse_StackOpIsEmpty( Parse_StackOp_t * p );
+extern void Parse_StackOpPush ( Parse_StackOp_t * p, int Oper );
+extern int Parse_StackOpPop ( Parse_StackOp_t * p );
+extern void Parse_StackOpFree ( Parse_StackOp_t * p );
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+#endif
diff --git a/src/bdd/parse/parseStack.c b/src/bdd/parse/parseStack.c
new file mode 100644
index 00000000..8329070e
--- /dev/null
+++ b/src/bdd/parse/parseStack.c
@@ -0,0 +1,243 @@
+/**CFile****************************************************************
+
+ FileName [parseStack.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Stacks used by the formula parser.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - August 18, 2003.]
+
+ Revision [$Id: parseStack.c,v 1.0 2003/02/01 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "parseInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+struct ParseStackFnStruct
+{
+ DdNode ** pData; // the array of elements
+ int Top; // the index
+ int Size; // the stack size
+};
+
+struct ParseStackOpStruct
+{
+ int * pData; // the array of elements
+ int Top; // the index
+ int Size; // the stack size
+};
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Starts the stack.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Parse_StackFn_t * Parse_StackFnStart( int nDepth )
+{
+ Parse_StackFn_t * p;
+ p = ALLOC( Parse_StackFn_t, 1 );
+ memset( p, 0, sizeof(Parse_StackFn_t) );
+ p->pData = ALLOC( DdNode *, nDepth );
+ p->Size = nDepth;
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks whether the stack is empty.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Parse_StackFnIsEmpty( Parse_StackFn_t * p )
+{
+ return (bool)(p->Top == 0);
+}
+
+/**Function*************************************************************
+
+ Synopsis [Pushes an entry into the stack.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Parse_StackFnPush( Parse_StackFn_t * p, DdNode * bFunc )
+{
+ if ( p->Top >= p->Size )
+ {
+ printf( "Parse_StackFnPush(): Stack size is too small!\n" );
+ return;
+ }
+ p->pData[ p->Top++ ] = bFunc;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Pops an entry out of the stack.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdNode * Parse_StackFnPop( Parse_StackFn_t * p )
+{
+ if ( p->Top == 0 )
+ {
+ printf( "Parse_StackFnPush(): Trying to extract data from the empty stack!\n" );
+ return NULL;
+ }
+ return p->pData[ --p->Top ];
+}
+
+/**Function*************************************************************
+
+ Synopsis [Deletes the stack.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Parse_StackFnFree( Parse_StackFn_t * p )
+{
+ FREE( p->pData );
+ FREE( p );
+}
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Starts the stack.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Parse_StackOp_t * Parse_StackOpStart( int nDepth )
+{
+ Parse_StackOp_t * p;
+ p = ALLOC( Parse_StackOp_t, 1 );
+ memset( p, 0, sizeof(Parse_StackOp_t) );
+ p->pData = ALLOC( int, nDepth );
+ p->Size = nDepth;
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks whether the stack is empty.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+bool Parse_StackOpIsEmpty( Parse_StackOp_t * p )
+{
+ return (bool)(p->Top == 0);
+}
+
+/**Function*************************************************************
+
+ Synopsis [Pushes an entry into the stack.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Parse_StackOpPush( Parse_StackOp_t * p, int Oper )
+{
+ if ( p->Top >= p->Size )
+ {
+ printf( "Parse_StackOpPush(): Stack size is too small!\n" );
+ return;
+ }
+ p->pData[ p->Top++ ] = Oper;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Pops an entry out of the stack.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Parse_StackOpPop( Parse_StackOp_t * p )
+{
+ if ( p->Top == 0 )
+ {
+ printf( "Parse_StackOpPush(): Trying to extract data from the empty stack!\n" );
+ return -1;
+ }
+ return p->pData[ --p->Top ];
+}
+
+/**Function*************************************************************
+
+ Synopsis [Deletes the stack.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Parse_StackOpFree( Parse_StackOp_t * p )
+{
+ FREE( p->pData );
+ FREE( p );
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/bdd/reo/module.make b/src/bdd/reo/module.make
new file mode 100644
index 00000000..703be139
--- /dev/null
+++ b/src/bdd/reo/module.make
@@ -0,0 +1,7 @@
+SRC += bdd\reo\reoApi.c \
+ bdd\reo\reoCore.c \
+ bdd\reo\reoProfile.c \
+ bdd\reo\reoSift.c \
+ bdd\reo\reoSwap.c \
+ bdd\reo\reoTransfer.c \
+ bdd\reo\reoUnits.c
diff --git a/src/bdd/reo/reo.h b/src/bdd/reo/reo.h
new file mode 100644
index 00000000..7e4be855
--- /dev/null
+++ b/src/bdd/reo/reo.h
@@ -0,0 +1,222 @@
+/**CFile****************************************************************
+
+ FileName [reo.h]
+
+ PackageName [REO: A specialized DD reordering engine.]
+
+ Synopsis [External and internal declarations.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - October 15, 2002.]
+
+ Revision [$Id: reo.h,v 1.0 2002/15/10 03:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __REO_H__
+#define __REO_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "extra.h"
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// reordering parameters
+#define REO_REORDER_LIMIT 1.15 // determines the quality/runtime trade-off
+#define REO_QUAL_PAR 3 // the quality [1 = simple lower bound, 2 = strict, larger = heuristic]
+// internal parameters
+#define REO_CONST_LEVEL 30000 // the number of the constant level
+#define REO_TOPREF_UNDEF 30000 // the undefined top reference
+#define REO_CHUNK_SIZE 5000 // the number of units allocated at one time
+#define REO_COST_EPSILON 0.0000001 // difference in cost large enough so that it counted as an error
+#define REO_HIGH_VALUE 10000000 // a large value used to initialize some variables
+// interface parameters
+#define REO_ENABLE 1 // the value of the enable flag
+#define REO_DISABLE 0 // the value of the disable flag
+
+// the types of minimization currently supported
+typedef enum {
+ REO_MINIMIZE_NODES,
+ REO_MINIMIZE_WIDTH, // may not work for BDDs with complemented edges
+ REO_MINIMIZE_APL
+} reo_min_type;
+
+////////////////////////////////////////////////////////////////////////
+/// DATA STRUCTURES ///
+////////////////////////////////////////////////////////////////////////
+
+typedef struct _reo_unit reo_unit; // the unit representing one DD node during reordering
+typedef struct _reo_plane reo_plane; // the set of nodes on one level
+typedef struct _reo_hash reo_hash; // the entry in the hash table
+typedef struct _reo_man reo_man; // the reordering manager
+typedef struct _reo_test reo_test; //
+
+struct _reo_unit
+{
+ short lev; // the level of this node at the beginning
+ short TopRef; // the top level from which this node is refed (used to update BDD width)
+ short TopRefNew; // the new top level from which this node is refed (used to update BDD width)
+ short n; // the number of incoming edges (similar to ref count in the BDD)
+ int Sign; // the signature
+
+ reo_unit * pE; // the pointer to the "else" branch
+ reo_unit * pT; // the pointer to the "then" branch
+ reo_unit * Next; // the link to the next one in the list
+ double Weight; // the probability of traversing this node
+};
+
+struct _reo_plane
+{
+ int fSifted; // to mark the sifted variables
+ int statsNodes; // the number of nodes in the current level
+ int statsWidth; // the width on the current level
+ double statsApl; // the sum of node probabilities on this level
+ double statsCost; // the current cost is stored here
+ double statsCostAbove; // the current cost is stored here
+ double statsCostBelow; // the current cost is stored here
+
+ reo_unit * pHead; // the pointer to the beginning of the unit list
+};
+
+struct _reo_hash
+{
+ int Sign; // signature of the current cache operation
+ unsigned Arg1; // the first argument
+ unsigned Arg2; // the second argument
+ unsigned Arg3; // the second argument
+};
+
+struct _reo_man
+{
+ // these paramaters can be set by the API functions
+ int fMinWidth; // the flag to enable reordering for minimum width
+ int fMinApl; // the flag to enable reordering for minimum APL
+ int fVerbose; // the verbosity level
+ int fVerify; // the flag toggling verification
+ int fRemapUp; // the flag to enable remapping
+ int nIters; // the number of interations of sifting to perform
+
+ // parameters given by the user when reordering is called
+ DdManager * dd; // the CUDD BDD manager
+ int * pOrder; // the resulting variable order will be returned here
+
+ // derived parameters
+ int fThisIsAdd; // this flag is one if the function is the ADD
+ int * pSupp; // the support of the given function
+ int nSuppAlloc; // the max allowed number of support variables
+ int nSupp; // the number of support variables
+ int * pOrderInt; // the array storing the internal variable permutation
+ double * pVarCosts; // other arrays
+ int * pLevelOrder; // other arrays
+ reo_unit ** pWidthCofs; // temporary storage for cofactors used during reordering for width
+
+ // parameters related to cost
+ int nNodesBeg;
+ int nNodesCur;
+ int nNodesEnd;
+ int nWidthCur;
+ int nWidthBeg;
+ int nWidthEnd;
+ double nAplCur;
+ double nAplBeg;
+ double nAplEnd;
+
+ // mapping of the function into planes and back
+ int * pMapToPlanes; // the mapping of var indexes into plane levels
+ int * pMapToDdVarsOrig;// the mapping of plane levels into the original indexes
+ int * pMapToDdVarsFinal;// the mapping of plane levels into the final indexes
+
+ // the planes table
+ reo_plane * pPlanes;
+ int nPlanes;
+ reo_unit ** pTops;
+ int nTops;
+ int nTopsAlloc;
+
+ // the hash table
+ reo_hash * HTable; // the table itself
+ int nTableSize; // the size of the hash table
+ int Signature; // the signature counter
+
+ // the referenced node list
+ int nNodesMaxAlloc; // this parameters determins how much memory is allocated
+ DdNode ** pRefNodes;
+ int nRefNodes;
+ int nRefNodesAlloc;
+
+ // unit memory management
+ reo_unit * pUnitFreeList;
+ reo_unit ** pMemChunks;
+ int nMemChunks;
+ int nMemChunksAlloc;
+ int nUnitsUsed;
+
+ // statistic variables
+ int HashSuccess;
+ int HashFailure;
+ int nSwaps; // the number of swaps
+ int nNISwaps; // the number of swaps without interaction
+};
+
+// used to manipulate units
+#define Unit_Regular(u) ((reo_unit *)((unsigned long)(u) & ~01))
+#define Unit_Not(u) ((reo_unit *)((long)(u) ^ 01))
+#define Unit_NotCond(u,c) ((reo_unit *)((long)(u) ^ (c)))
+#define Unit_IsConstant(u) ((int)((u)->lev == REO_CONST_LEVEL))
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// ======================= reoApi.c ========================================
+extern reo_man * Extra_ReorderInit( int nDdVarsMax, int nNodesMax );
+extern void Extra_ReorderQuit( reo_man * p );
+extern void Extra_ReorderSetMinimizationType( reo_man * p, reo_min_type fMinType );
+extern void Extra_ReorderSetRemapping( reo_man * p, int fRemapUp );
+extern void Extra_ReorderSetIterations( reo_man * p, int nIters );
+extern void Extra_ReorderSetVerbosity( reo_man * p, int fVerbose );
+extern void Extra_ReorderSetVerification( reo_man * p, int fVerify );
+extern DdNode * Extra_Reorder( reo_man * p, DdManager * dd, DdNode * Func, int * pOrder );
+extern void Extra_ReorderArray( reo_man * p, DdManager * dd, DdNode * Funcs[], DdNode * FuncsRes[], int nFuncs, int * pOrder );
+// ======================= reoCore.c =======================================
+extern void reoReorderArray( reo_man * p, DdManager * dd, DdNode * Funcs[], DdNode * FuncsRes[], int nFuncs, int * pOrder );
+extern void reoResizeStructures( reo_man * p, int nDdVarsMax, int nNodesMax, int nFuncs );
+// ======================= reoProfile.c ======================================
+extern void reoProfileNodesStart( reo_man * p );
+extern void reoProfileAplStart( reo_man * p );
+extern void reoProfileWidthStart( reo_man * p );
+extern void reoProfileWidthStart2( reo_man * p );
+extern void reoProfileAplPrint( reo_man * p );
+extern void reoProfileNodesPrint( reo_man * p );
+extern void reoProfileWidthPrint( reo_man * p );
+extern void reoProfileWidthVerifyLevel( reo_plane * pPlane, int Level );
+// ======================= reoSift.c =======================================
+extern void reoReorderSift( reo_man * p );
+// ======================= reoSwap.c =======================================
+extern double reoReorderSwapAdjacentVars( reo_man * p, int Level, int fMovingUp );
+// ======================= reoTransfer.c ===================================
+extern reo_unit * reoTransferNodesToUnits_rec( reo_man * p, DdNode * F );
+extern DdNode * reoTransferUnitsToNodes_rec( reo_man * p, reo_unit * pUnit );
+// ======================= reoUnits.c ======================================
+extern reo_unit * reoUnitsGetNextUnit(reo_man * p );
+extern void reoUnitsRecycleUnit( reo_man * p, reo_unit * pUnit );
+extern void reoUnitsRecycleUnitList( reo_man * p, reo_plane * pPlane );
+extern void reoUnitsAddUnitToPlane( reo_plane * pPlane, reo_unit * pUnit );
+extern void reoUnitsStopDispenser( reo_man * p );
+// ======================= reoTest.c =======================================
+extern void Extra_ReorderTest( DdManager * dd, DdNode * Func );
+extern DdNode * Extra_ReorderCudd( DdManager * dd, DdNode * aFunc, int pPermuteReo[] );
+extern int Extra_bddReorderTest( DdManager * dd, DdNode * bF );
+extern int Extra_addReorderTest( DdManager * dd, DdNode * aF );
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+#endif
diff --git a/src/bdd/reo/reoApi.c b/src/bdd/reo/reoApi.c
new file mode 100644
index 00000000..e833dabd
--- /dev/null
+++ b/src/bdd/reo/reoApi.c
@@ -0,0 +1,289 @@
+/**CFile****************************************************************
+
+ FileName [reoApi.c]
+
+ PackageName [REO: A specialized DD reordering engine.]
+
+ Synopsis [Implementation of API functions.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - October 15, 2002.]
+
+ Revision [$Id: reoApi.c,v 1.0 2002/15/10 03:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "reo.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Initializes the reordering engine.]
+
+ Description [The first argument is the max number of variables in the
+ CUDD DD manager which will be used with the reordering engine
+ (this number of should be the maximum of BDD and ZDD parts).
+ The second argument is the maximum number of BDD nodes in the BDDs
+ to be reordered. These limits are soft. Setting lower limits will later
+ cause the reordering manager to resize internal data structures.
+ However, setting the exact values will make reordering more efficient
+ because resizing will be not necessary.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+reo_man * Extra_ReorderInit( int nDdVarsMax, int nNodesMax )
+{
+ reo_man * p;
+ // allocate and clean the data structure
+ p = ALLOC( reo_man, 1 );
+ memset( p, 0, sizeof(reo_man) );
+ // resize the manager to meet user's needs
+ reoResizeStructures( p, nDdVarsMax, nNodesMax, 100 );
+ // set the defaults
+ p->fMinApl = 0;
+ p->fMinWidth = 0;
+ p->fRemapUp = 0;
+ p->fVerbose = 0;
+ p->fVerify = 0;
+ p->nIters = 1;
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Disposes of the reordering engine.]
+
+ Description [Removes all memory associated with the reordering engine.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_ReorderQuit( reo_man * p )
+{
+ free( p->pTops );
+ free( p->pSupp );
+ free( p->pOrderInt );
+ free( p->pWidthCofs );
+ free( p->pMapToPlanes );
+ free( p->pMapToDdVarsOrig );
+ free( p->pMapToDdVarsFinal );
+ free( p->pPlanes );
+ free( p->pVarCosts );
+ free( p->pLevelOrder );
+ free( p->HTable );
+ free( p->pRefNodes );
+ reoUnitsStopDispenser( p );
+ free( p->pMemChunks );
+ free( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the type of DD minimizationl that will be performed.]
+
+ Description [Currently, three different types of minimization are supported.
+ It is possible to minimize the number of BDD nodes. This is a classical type
+ of minimization, which is attempting to reduce the total number of nodes in
+ the (shared) BDD of the given Boolean functions. It is also possible to
+ minimize the BDD width, defined as the sum total of the number of cofactors
+ on each level in the (shared) BDD (note that the number of cofactors on the
+ given level may be larger than the number of nodes appearing on the given level).
+ It is also possible to minimize the average path length in the (shared) BDD
+ defined as the sum of products, for all BDD paths from the top node to any
+ terminal node, of the number of minterms on the path by the number of nodes
+ on the path. The default reordering type is minimization for the number of
+ BDD nodes. Calling this function with REO_MINIMIZE_WIDTH or REO_MINIMIZE_APL
+ as the second argument, changes the default minimization option for all the
+ reorder calls performed afterwards.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_ReorderSetMinimizationType( reo_man * p, reo_min_type fMinType )
+{
+ if ( fMinType == REO_MINIMIZE_NODES )
+ {
+ p->fMinWidth = 0;
+ p->fMinApl = 0;
+ }
+ else if ( fMinType == REO_MINIMIZE_WIDTH )
+ {
+ p->fMinWidth = 1;
+ p->fMinApl = 0;
+ }
+ else if ( fMinType == REO_MINIMIZE_APL )
+ {
+ p->fMinWidth = 0;
+ p->fMinApl = 1;
+ }
+ else
+ {
+ assert( 0 );
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the type of remapping performed by the engine.]
+
+ Description [The remapping refers to the way the resulting BDD
+ is expressed using the elementary variables of the CUDD BDD manager.
+ Currently, two types possibilities are supported: remapping and no
+ remapping. Remapping means that the function(s) after reordering
+ depend on the topmost variables in the manager. No remapping means
+ that the function(s) after reordering depend on the same variables
+ as before. Consider the following example. Suppose the initial four
+ variable function depends on variables 2,4,5, and 9 on the CUDD BDD
+ manager, which may be found anywhere in the current variable order.
+ If remapping is set, the function after ordering depends on the
+ topmost variables in the manager, which may or may not be the same
+ as the variables 2,4,5, and 9. If no remapping is set, then the
+ reordered function depend on the same variables 2,4,5, and 9, but
+ the meaning of each variale has changed according to the new ordering.
+ The resulting ordering is returned in the array "pOrder" filled out
+ by the reordering engine in the call to Extra_Reorder(). The default
+ is no remapping.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_ReorderSetRemapping( reo_man * p, int fRemapUp )
+{
+ p->fRemapUp = fRemapUp;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the number of iterations of sifting performed.]
+
+ Description [The default is one iteration. But a higher minimization
+ quality is desired, it is possible to set the number of iterations
+ to any number larger than 1. Convergence is often reached after
+ several iterations, so typically it make no sense to set the number
+ of iterations higher than 3.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_ReorderSetIterations( reo_man * p, int nIters )
+{
+ p->nIters = nIters;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the verification mode.]
+
+ Description [Setting the level to 1 results in verifying the results
+ of variable reordering. Verification is performed by remapping the
+ resulting functions into the original variable order and comparing
+ them with the original functions given by the user. Enabling verification
+ typically leads to 20-30% increase in the total runtime of REO.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_ReorderSetVerification( reo_man * p, int fVerify )
+{
+ p->fVerify = fVerify;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the verbosity level.]
+
+ Description [Setting the level to 1 results in printing statistics
+ before and after the reordering.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_ReorderSetVerbosity( reo_man * p, int fVerbose )
+{
+ p->fVerbose = fVerbose;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs reordering of the function.]
+
+ Description [Returns the DD minimized by variable reordering in the REO
+ engine. Takes the CUDD decision diagram manager (dd) and the function (Func)
+ represented as a BDD or ADD (MTBDD). If the variable array (pOrder) is not NULL,
+ returns the resulting variable permutation. The permutation is such that if the resulting
+ function is permuted by Cudd_(add,bdd)Permute() using pOrder as the permutation
+ array, the initial function (Func) results.
+ Several flag set by other interface functions specify reordering options:
+ - Remappig can be set by Extra_ReorderSetRemapping(). Then the resulting DD after
+ reordering is remapped into the topmost levels of the DD manager. Otherwise,
+ the resulting DD after reordering is mapped using the same variables, on which it
+ originally depended, only (possibly) permuted as a result of reordering.
+ - Minimization type can be set by Extra_ReorderSetMinimizationType(). Note
+ that when the BDD is minimized for the total width of the total APL, the number
+ BDD nodes can increase. The total width is defines as sum total of widths on each
+ level. The width on one level is defined as the number of distinct BDD nodes
+ pointed by the nodes situated above the given level.
+ - The number of iterations of sifting can be set by Extra_ReorderSetIterations().
+ The decision diagram returned by this procedure is not referenced.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdNode * Extra_Reorder( reo_man * p, DdManager * dd, DdNode * Func, int * pOrder )
+{
+ DdNode * FuncRes;
+ Extra_ReorderArray( p, dd, &Func, &FuncRes, 1, pOrder );
+ Cudd_Deref( FuncRes );
+ return FuncRes;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs reordering of the array of functions.]
+
+ Description [The options are similar to the procedure Extra_Reorder(), except that
+ the user should also provide storage for the resulting DDs, which are returned
+ referenced.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_ReorderArray( reo_man * p, DdManager * dd, DdNode * Funcs[], DdNode * FuncsRes[], int nFuncs, int * pOrder )
+{
+ reoReorderArray( p, dd, Funcs, FuncsRes, nFuncs, pOrder );
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
diff --git a/src/bdd/reo/reoCore.c b/src/bdd/reo/reoCore.c
new file mode 100644
index 00000000..3782631c
--- /dev/null
+++ b/src/bdd/reo/reoCore.c
@@ -0,0 +1,438 @@
+/**CFile****************************************************************
+
+ FileName [reoCore.c]
+
+ PackageName [REO: A specialized DD reordering engine.]
+
+ Synopsis [Implementation of the core reordering procedure.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - October 15, 2002.]
+
+ Revision [$Id: reoCore.c,v 1.0 2002/15/10 03:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "reo.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+#define CALLOC(type, num) ((type *) calloc((long)(num), (long)sizeof(type)))
+
+static int reoRecursiveDeref( reo_unit * pUnit );
+static int reoCheckZeroRefs( reo_plane * pPlane );
+static int reoCheckLevels( reo_man * p );
+
+double s_AplBefore;
+double s_AplAfter;
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void reoReorderArray( reo_man * p, DdManager * dd, DdNode * Funcs[], DdNode * FuncsRes[], int nFuncs, int * pOrder )
+{
+ int Counter, i;
+
+ // set the initial parameters
+ p->dd = dd;
+ p->pOrder = pOrder;
+ p->nTops = nFuncs;
+ // get the initial number of nodes
+ p->nNodesBeg = Cudd_SharingSize( Funcs, nFuncs );
+ // resize the internal data structures of the manager if necessary
+ reoResizeStructures( p, ddMax(dd->size,dd->sizeZ), p->nNodesBeg, nFuncs );
+ // compute the support
+ p->pSupp = Extra_VectorSupportArray( dd, Funcs, nFuncs, p->pSupp );
+ // get the number of support variables
+ p->nSupp = 0;
+ for ( i = 0; i < dd->size; i++ )
+ p->nSupp += p->pSupp[i];
+
+ // if it is the constant function, no need to reorder
+ if ( p->nSupp == 0 )
+ {
+ for ( i = 0; i < nFuncs; i++ )
+ {
+ FuncsRes[i] = Funcs[i]; Cudd_Ref( FuncsRes[i] );
+ }
+ return;
+ }
+
+ // create the internal variable maps
+ // go through variable levels in the manager
+ Counter = 0;
+ for ( i = 0; i < dd->size; i++ )
+ if ( p->pSupp[ dd->invperm[i] ] )
+ {
+ p->pMapToPlanes[ dd->invperm[i] ] = Counter;
+ p->pMapToDdVarsOrig[Counter] = dd->invperm[i];
+ if ( !p->fRemapUp )
+ p->pMapToDdVarsFinal[Counter] = dd->invperm[i];
+ else
+ p->pMapToDdVarsFinal[Counter] = dd->invperm[Counter];
+ p->pOrderInt[Counter] = Counter;
+ Counter++;
+ }
+
+ // set the initial parameters
+ p->nUnitsUsed = 0;
+ p->nNodesCur = 0;
+ p->fThisIsAdd = 0;
+ p->Signature++;
+ // transfer the function from the CUDD package into REO"s internal data structure
+ for ( i = 0; i < nFuncs; i++ )
+ p->pTops[i] = reoTransferNodesToUnits_rec( p, Funcs[i] );
+ assert( p->nNodesBeg == p->nNodesCur );
+
+ if ( !p->fThisIsAdd && p->fMinWidth )
+ {
+ printf( "An important message from the REO reordering engine:\n" );
+ printf( "The BDD given to the engine for reordering contains complemented edges.\n" );
+ printf( "Currently, such BDDs cannot be reordered for the minimum width.\n" );
+ printf( "Therefore, minimization for the number of BDD nodes is performed.\n" );
+ fflush( stdout );
+ p->fMinApl = 0;
+ p->fMinWidth = 0;
+ }
+
+ if ( p->fMinWidth )
+ reoProfileWidthStart(p);
+ else if ( p->fMinApl )
+ reoProfileAplStart(p);
+ else
+ reoProfileNodesStart(p);
+
+ if ( p->fVerbose )
+ {
+ printf( "INITIAL: " );
+ if ( p->fMinWidth )
+ reoProfileWidthPrint(p);
+ else if ( p->fMinApl )
+ reoProfileAplPrint(p);
+ else
+ reoProfileNodesPrint(p);
+ }
+
+ ///////////////////////////////////////////////////////////////////
+ // performs the reordering
+ p->nSwaps = 0;
+ p->nNISwaps = 0;
+ for ( i = 0; i < p->nIters; i++ )
+ {
+ reoReorderSift( p );
+ // print statistics after each iteration
+ if ( p->fVerbose )
+ {
+ printf( "ITER #%d: ", i+1 );
+ if ( p->fMinWidth )
+ reoProfileWidthPrint(p);
+ else if ( p->fMinApl )
+ reoProfileAplPrint(p);
+ else
+ reoProfileNodesPrint(p);
+ }
+ // if the cost function did not change, stop iterating
+ if ( p->fMinWidth )
+ {
+ p->nWidthEnd = p->nWidthCur;
+ assert( p->nWidthEnd <= p->nWidthBeg );
+ if ( p->nWidthEnd == p->nWidthBeg )
+ break;
+ }
+ else if ( p->fMinApl )
+ {
+ p->nAplEnd = p->nAplCur;
+ assert( p->nAplEnd <= p->nAplBeg );
+ if ( p->nAplEnd == p->nAplBeg )
+ break;
+ }
+ else
+ {
+ p->nNodesEnd = p->nNodesCur;
+ assert( p->nNodesEnd <= p->nNodesBeg );
+ if ( p->nNodesEnd == p->nNodesBeg )
+ break;
+ }
+ }
+ assert( reoCheckLevels( p ) );
+ ///////////////////////////////////////////////////////////////////
+
+s_AplBefore = p->nAplBeg;
+s_AplAfter = p->nAplEnd;
+
+ // set the initial parameters
+ p->nRefNodes = 0;
+ p->nNodesCur = 0;
+ p->Signature++;
+ // transfer the BDDs from REO's internal data structure to CUDD
+ for ( i = 0; i < nFuncs; i++ )
+ {
+ FuncsRes[i] = reoTransferUnitsToNodes_rec( p, p->pTops[i] ); Cudd_Ref( FuncsRes[i] );
+ }
+ // undo the DDs referenced for storing in the cache
+ for ( i = 0; i < p->nRefNodes; i++ )
+ Cudd_RecursiveDeref( dd, p->pRefNodes[i] );
+ // verify zero refs of the terminal nodes
+ for ( i = 0; i < nFuncs; i++ )
+ {
+ assert( reoRecursiveDeref( p->pTops[i] ) );
+ }
+ assert( reoCheckZeroRefs( &(p->pPlanes[p->nSupp]) ) );
+
+ // prepare the variable map to return to the user
+ if ( p->pOrder )
+ {
+ // i is the current level in the planes data structure
+ // p->pOrderInt[i] is the original level in the planes data structure
+ // p->pMapToDdVarsOrig[i] is the variable, into which we remap when we construct the BDD from planes
+ // p->pMapToDdVarsOrig[ p->pOrderInt[i] ] is the original BDD variable corresponding to this level
+ // Therefore, p->pOrder[ p->pMapToDdVarsFinal[i] ] = p->pMapToDdVarsOrig[ p->pOrderInt[i] ]
+ // creates the permutation, which remaps the resulting BDD variable into the original BDD variable
+ for ( i = 0; i < p->nSupp; i++ )
+ p->pOrder[ p->pMapToDdVarsFinal[i] ] = p->pMapToDdVarsOrig[ p->pOrderInt[i] ];
+ }
+
+ if ( p->fVerify )
+ {
+ int fVerification;
+ DdNode * FuncRemapped;
+ int * pOrder;
+
+ if ( p->pOrder == NULL )
+ {
+ pOrder = ALLOC( int, p->nSupp );
+ for ( i = 0; i < p->nSupp; i++ )
+ pOrder[ p->pMapToDdVarsFinal[i] ] = p->pMapToDdVarsOrig[ p->pOrderInt[i] ];
+ }
+ else
+ pOrder = p->pOrder;
+
+ fVerification = 1;
+ for ( i = 0; i < nFuncs; i++ )
+ {
+ // verify the result
+ if ( p->fThisIsAdd )
+ FuncRemapped = Cudd_addPermute( dd, FuncsRes[i], pOrder );
+ else
+ FuncRemapped = Cudd_bddPermute( dd, FuncsRes[i], pOrder );
+ Cudd_Ref( FuncRemapped );
+
+ if ( FuncRemapped != Funcs[i] )
+ {
+ fVerification = 0;
+ printf( "REO: Internal verification has failed!\n" );
+ fflush( stdout );
+ }
+ Cudd_RecursiveDeref( dd, FuncRemapped );
+ }
+ if ( fVerification )
+ printf( "REO: Internal verification is okay!\n" );
+
+ if ( p->pOrder == NULL )
+ free( pOrder );
+ }
+
+ // recycle the data structure
+ for ( i = 0; i <= p->nSupp; i++ )
+ reoUnitsRecycleUnitList( p, p->pPlanes + i );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Resizes the internal manager data structures.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void reoResizeStructures( reo_man * p, int nDdVarsMax, int nNodesMax, int nFuncs )
+{
+ // resize data structures depending on the number of variables in the DD manager
+ if ( p->nSuppAlloc == 0 )
+ {
+ p->pSupp = ALLOC( int, nDdVarsMax + 1 );
+ p->pOrderInt = ALLOC( int, nDdVarsMax + 1 );
+ p->pMapToPlanes = ALLOC( int, nDdVarsMax + 1 );
+ p->pMapToDdVarsOrig = ALLOC( int, nDdVarsMax + 1 );
+ p->pMapToDdVarsFinal = ALLOC( int, nDdVarsMax + 1 );
+ p->pPlanes = CALLOC( reo_plane, nDdVarsMax + 1 );
+ p->pVarCosts = ALLOC( double, nDdVarsMax + 1 );
+ p->pLevelOrder = ALLOC( int, nDdVarsMax + 1 );
+ p->nSuppAlloc = nDdVarsMax + 1;
+ }
+ else if ( p->nSuppAlloc < nDdVarsMax )
+ {
+ free( p->pSupp );
+ free( p->pOrderInt );
+ free( p->pMapToPlanes );
+ free( p->pMapToDdVarsOrig );
+ free( p->pMapToDdVarsFinal );
+ free( p->pPlanes );
+ free( p->pVarCosts );
+ free( p->pLevelOrder );
+
+ p->pSupp = ALLOC( int, nDdVarsMax + 1 );
+ p->pOrderInt = ALLOC( int, nDdVarsMax + 1 );
+ p->pMapToPlanes = ALLOC( int, nDdVarsMax + 1 );
+ p->pMapToDdVarsOrig = ALLOC( int, nDdVarsMax + 1 );
+ p->pMapToDdVarsFinal = ALLOC( int, nDdVarsMax + 1 );
+ p->pPlanes = CALLOC( reo_plane, nDdVarsMax + 1 );
+ p->pVarCosts = ALLOC( double, nDdVarsMax + 1 );
+ p->pLevelOrder = ALLOC( int, nDdVarsMax + 1 );
+ p->nSuppAlloc = nDdVarsMax + 1;
+ }
+
+ // resize the data structures depending on the number of nodes
+ if ( p->nRefNodesAlloc == 0 )
+ {
+ p->nNodesMaxAlloc = nNodesMax;
+ p->nTableSize = 3*nNodesMax + 1;
+ p->nRefNodesAlloc = 3*nNodesMax + 1;
+ p->nMemChunksAlloc = (10*nNodesMax + 1)/REO_CHUNK_SIZE + 1;
+
+ p->HTable = CALLOC( reo_hash, p->nTableSize );
+ p->pRefNodes = ALLOC( DdNode *, p->nRefNodesAlloc );
+ p->pWidthCofs = ALLOC( reo_unit *, p->nRefNodesAlloc );
+ p->pMemChunks = ALLOC( reo_unit *, p->nMemChunksAlloc );
+ }
+ else if ( p->nNodesMaxAlloc < nNodesMax )
+ {
+ void * pTemp;
+ int nMemChunksAllocPrev = p->nMemChunksAlloc;
+
+ p->nNodesMaxAlloc = nNodesMax;
+ p->nTableSize = 3*nNodesMax + 1;
+ p->nRefNodesAlloc = 3*nNodesMax + 1;
+ p->nMemChunksAlloc = (10*nNodesMax + 1)/REO_CHUNK_SIZE + 1;
+
+ free( p->HTable );
+ free( p->pRefNodes );
+ free( p->pWidthCofs );
+ p->HTable = CALLOC( reo_hash, p->nTableSize );
+ p->pRefNodes = ALLOC( DdNode *, p->nRefNodesAlloc );
+ p->pWidthCofs = ALLOC( reo_unit *, p->nRefNodesAlloc );
+ // p->pMemChunks should be reallocated because it contains pointers currently in use
+ pTemp = ALLOC( reo_unit *, p->nMemChunksAlloc );
+ memmove( pTemp, p->pMemChunks, sizeof(reo_unit *) * nMemChunksAllocPrev );
+ free( p->pMemChunks );
+ p->pMemChunks = pTemp;
+ }
+
+ // resize the data structures depending on the number of functions
+ if ( p->nTopsAlloc == 0 )
+ {
+ p->pTops = ALLOC( reo_unit *, nFuncs );
+ p->nTopsAlloc = nFuncs;
+ }
+ else if ( p->nTopsAlloc < nFuncs )
+ {
+ free( p->pTops );
+ p->pTops = ALLOC( reo_unit *, nFuncs );
+ p->nTopsAlloc = nFuncs;
+ }
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Dereferences units the data structure after reordering.]
+
+ Description [This function is only useful for debugging.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int reoRecursiveDeref( reo_unit * pUnit )
+{
+ reo_unit * pUnitR;
+ pUnitR = Unit_Regular(pUnit);
+ pUnitR->n--;
+ if ( Unit_IsConstant(pUnitR) )
+ return 1;
+ if ( pUnitR->n == 0 )
+ {
+ reoRecursiveDeref( pUnitR->pE );
+ reoRecursiveDeref( pUnitR->pT );
+ }
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks the zero references for the given plane.]
+
+ Description [This function is only useful for debugging.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int reoCheckZeroRefs( reo_plane * pPlane )
+{
+ reo_unit * pUnit;
+ for ( pUnit = pPlane->pHead; pUnit; pUnit = pUnit->Next )
+ {
+ if ( pUnit->n != 0 )
+ {
+ assert( 0 );
+ }
+ }
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks the zero references for the given plane.]
+
+ Description [This function is only useful for debugging.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int reoCheckLevels( reo_man * p )
+{
+ reo_unit * pUnit;
+ int i;
+
+ for ( i = 0; i < p->nSupp; i++ )
+ {
+ // there are some nodes left on each level
+ assert( p->pPlanes[i].statsNodes );
+ for ( pUnit = p->pPlanes[i].pHead; pUnit; pUnit = pUnit->Next )
+ {
+ // the level is properly set
+ assert( pUnit->lev == i );
+ }
+ }
+ return 1;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
diff --git a/src/bdd/reo/reoProfile.c b/src/bdd/reo/reoProfile.c
new file mode 100644
index 00000000..b38575f0
--- /dev/null
+++ b/src/bdd/reo/reoProfile.c
@@ -0,0 +1,365 @@
+/**CFile****************************************************************
+
+ FileName [reoProfile.c]
+
+ PackageName [REO: A specialized DD reordering engine.]
+
+ Synopsis [Procudures that compute variables profiles (nodes, width, APL).]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - October 15, 2002.]
+
+ Revision [$Id: reoProfile.c,v 1.0 2002/15/10 03:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "reo.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+
+/**Function********************************************************************
+
+ Synopsis [Start the profile for the BDD nodes.]
+
+ Description [TopRef is the first level, on this the given node counts towards
+ the width of the BDDs. (In other words, it is the level of the referencing node plus 1.)]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void reoProfileNodesStart( reo_man * p )
+{
+ int Total, i;
+ Total = 0;
+ for ( i = 0; i <= p->nSupp; i++ )
+ {
+ p->pPlanes[i].statsCost = p->pPlanes[i].statsNodes;
+ Total += p->pPlanes[i].statsNodes;
+ }
+ assert( Total == p->nNodesCur );
+ p->nNodesBeg = p->nNodesCur;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Start the profile for the APL.]
+
+ Description [Computes the total path length. The path length is normalized
+ by dividing it by 2^|supp(f)|. To get the "real" APL, multiply by 2^|supp(f)|.
+ This procedure assumes that Weight field of all nodes has been set to 0.0
+ before the call, except for the weight of the topmost node, which is set to 1.0
+ (1.0 is the probability of traversing the topmost node). This procedure
+ assigns the edge weights. Because of the equal probability of selecting 0 and 1
+ assignment at a node, the edge weights are the same for the node.
+ Instead of storing them, we store the weight of the node, which is the probability
+ of traversing the node (pUnit->Weight) during the top down evalation of the BDD. ]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void reoProfileAplStart( reo_man * p )
+{
+ reo_unit * pER, * pTR;
+ reo_unit * pUnit;
+ double Res, Half;
+ int i;
+
+ // clean the weights of all nodes
+ for ( i = 0; i < p->nSupp; i++ )
+ for ( pUnit = p->pPlanes[i].pHead; pUnit; pUnit = pUnit->Next )
+ pUnit->Weight = 0.0;
+ // to assign the node weights (the probability of visiting each node)
+ // we visit the node after visiting its predecessors
+
+ // set the probability of visits to the top nodes
+ for ( i = 0; i < p->nTops; i++ )
+ Unit_Regular(p->pTops[i])->Weight += 1.0;
+
+ // to compute the path length (the sum of products of edge weight by edge length)
+ // we visit the nodes in any order (the above order will do)
+ Res = 0.0;
+ for ( i = 0; i < p->nSupp; i++ )
+ {
+ p->pPlanes[i].statsCost = 0.0;
+ for ( pUnit = p->pPlanes[i].pHead; pUnit; pUnit = pUnit->Next )
+ {
+ pER = Unit_Regular(pUnit->pE);
+ pTR = Unit_Regular(pUnit->pT);
+ Half = 0.5 * pUnit->Weight;
+ pER->Weight += Half;
+ pTR->Weight += Half;
+ // add to the path length
+ p->pPlanes[i].statsCost += pUnit->Weight;
+ }
+ Res += p->pPlanes[i].statsCost;
+ }
+ p->pPlanes[p->nSupp].statsCost = 0.0;
+ p->nAplBeg = p->nAplCur = Res;
+}
+
+/**Function********************************************************************
+
+ Synopsis [Start the profile for the BDD width. Complexity of the algorithm is O(N + n).]
+
+ Description [TopRef is the first level, on which the given node counts towards
+ the width of the BDDs. (In other words, it is the level of the referencing node plus 1.)]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void reoProfileWidthStart( reo_man * p )
+{
+ reo_unit * pUnit;
+ int * pWidthStart;
+ int * pWidthStop;
+ int v;
+
+ // allocate and clean the storage for starting and stopping levels
+ pWidthStart = ALLOC( int, p->nSupp + 1 );
+ pWidthStop = ALLOC( int, p->nSupp + 1 );
+ memset( pWidthStart, 0, sizeof(int) * (p->nSupp + 1) );
+ memset( pWidthStop, 0, sizeof(int) * (p->nSupp + 1) );
+
+ // go through the non-constant nodes and set the topmost level of their cofactors
+ for ( v = 0; v <= p->nSupp; v++ )
+ for ( pUnit = p->pPlanes[v].pHead; pUnit; pUnit = pUnit->Next )
+ {
+ pUnit->TopRef = REO_TOPREF_UNDEF;
+ pUnit->Sign = 0;
+ }
+
+ // add the topmost level of the width profile
+ for ( v = 0; v < p->nTops; v++ )
+ {
+ pUnit = Unit_Regular(p->pTops[v]);
+ if ( pUnit->TopRef == REO_TOPREF_UNDEF )
+ {
+ // set the starting level
+ pUnit->TopRef = 0;
+ pWidthStart[pUnit->TopRef]++;
+ // set the stopping level
+ if ( pUnit->lev != REO_CONST_LEVEL )
+ pWidthStop[pUnit->lev+1]++;
+ }
+ }
+
+ for ( v = 0; v < p->nSupp; v++ )
+ for ( pUnit = p->pPlanes[v].pHead; pUnit; pUnit = pUnit->Next )
+ {
+ if ( pUnit->pE->TopRef == REO_TOPREF_UNDEF )
+ {
+ // set the starting level
+ pUnit->pE->TopRef = pUnit->lev + 1;
+ pWidthStart[pUnit->pE->TopRef]++;
+ // set the stopping level
+ if ( pUnit->pE->lev != REO_CONST_LEVEL )
+ pWidthStop[pUnit->pE->lev+1]++;
+ }
+ if ( pUnit->pT->TopRef == REO_TOPREF_UNDEF )
+ {
+ // set the starting level
+ pUnit->pT->TopRef = pUnit->lev + 1;
+ pWidthStart[pUnit->pT->TopRef]++;
+ // set the stopping level
+ if ( pUnit->pT->lev != REO_CONST_LEVEL )
+ pWidthStop[pUnit->pT->lev+1]++;
+ }
+ }
+
+ // verify the top reference
+ for ( v = 0; v < p->nSupp; v++ )
+ reoProfileWidthVerifyLevel( p->pPlanes + v, v );
+
+ // derive the profile
+ p->nWidthCur = 0;
+ for ( v = 0; v <= p->nSupp; v++ )
+ {
+ if ( v == 0 )
+ p->pPlanes[v].statsWidth = pWidthStart[v] - pWidthStop[v];
+ else
+ p->pPlanes[v].statsWidth = p->pPlanes[v-1].statsWidth + pWidthStart[v] - pWidthStop[v];
+ p->pPlanes[v].statsCost = p->pPlanes[v].statsWidth;
+ p->nWidthCur += p->pPlanes[v].statsWidth;
+// printf( "Level %2d: Width = %5d. Correct = %d.\n", v, Temp, p->pPlanes[v].statsWidth );
+ }
+ p->nWidthBeg = p->nWidthCur;
+ free( pWidthStart );
+ free( pWidthStop );
+}
+
+/**Function********************************************************************
+
+ Synopsis [Start the profile for the BDD width. Complexity of the algorithm is O(N * n).]
+
+ Description [TopRef is the first level, on which the given node counts towards
+ the width of the BDDs. (In other words, it is the level of the referencing node plus 1.)]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void reoProfileWidthStart2( reo_man * p )
+{
+ reo_unit * pUnit;
+ int i, v;
+
+ // clean the profile
+ for ( i = 0; i <= p->nSupp; i++ )
+ p->pPlanes[i].statsWidth = 0;
+
+ // clean the node structures
+ for ( v = 0; v <= p->nSupp; v++ )
+ for ( pUnit = p->pPlanes[v].pHead; pUnit; pUnit = pUnit->Next )
+ {
+ pUnit->TopRef = REO_TOPREF_UNDEF;
+ pUnit->Sign = 0;
+ }
+
+ // set the topref to the topmost nodes
+ for ( i = 0; i < p->nTops; i++ )
+ Unit_Regular(p->pTops[i])->TopRef = 0;
+
+ // go through the non-constant nodes and set the topmost level of their cofactors
+ for ( i = 0; i < p->nSupp; i++ )
+ for ( pUnit = p->pPlanes[i].pHead; pUnit; pUnit = pUnit->Next )
+ {
+ if ( pUnit->pE->TopRef > i+1 )
+ pUnit->pE->TopRef = i+1;
+ if ( pUnit->pT->TopRef > i+1 )
+ pUnit->pT->TopRef = i+1;
+ }
+
+ // verify the top reference
+ for ( i = 0; i < p->nSupp; i++ )
+ reoProfileWidthVerifyLevel( p->pPlanes + i, i );
+
+ // compute the profile for the internal nodes
+ for ( i = 0; i < p->nSupp; i++ )
+ for ( pUnit = p->pPlanes[i].pHead; pUnit; pUnit = pUnit->Next )
+ for ( v = pUnit->TopRef; v <= pUnit->lev; v++ )
+ p->pPlanes[v].statsWidth++;
+
+ // compute the profile for the constant nodes
+ for ( pUnit = p->pPlanes[p->nSupp].pHead; pUnit; pUnit = pUnit->Next )
+ for ( v = pUnit->TopRef; v <= p->nSupp; v++ )
+ p->pPlanes[v].statsWidth++;
+
+ // get the width cost
+ p->nWidthCur = 0;
+ for ( i = 0; i <= p->nSupp; i++ )
+ {
+ p->pPlanes[i].statsCost = p->pPlanes[i].statsWidth;
+ p->nWidthCur += p->pPlanes[i].statsWidth;
+ }
+ p->nWidthBeg = p->nWidthCur;
+}
+
+/**Function********************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void reoProfileNodesPrint( reo_man * p )
+{
+ printf( "NODES: Total = %6d. Average = %6.2f.\n", p->nNodesCur, p->nNodesCur / (float)p->nSupp );
+}
+
+/**Function********************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void reoProfileAplPrint( reo_man * p )
+{
+ printf( "APL: Total = %8.2f. Average =%6.2f.\n", p->nAplCur, p->nAplCur / (float)p->nSupp );
+}
+
+/**Function********************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void reoProfileWidthPrint( reo_man * p )
+{
+ int WidthMax;
+ int TotalWidth;
+ int i;
+
+ WidthMax = 0;
+ TotalWidth = 0;
+ for ( i = 0; i <= p->nSupp; i++ )
+ {
+// printf( "Level = %2d. Width = %3d.\n", i, p->pProfile[i] );
+ if ( WidthMax < p->pPlanes[i].statsWidth )
+ WidthMax = p->pPlanes[i].statsWidth;
+ TotalWidth += p->pPlanes[i].statsWidth;
+ }
+ assert( p->nWidthCur = TotalWidth );
+ printf( "WIDTH: " );
+ printf( "Maximum = %5d. ", WidthMax );
+ printf( "Total = %7d. ", p->nWidthCur );
+ printf( "Average = %6.2f.\n", TotalWidth / (float)p->nSupp );
+}
+
+/**Function********************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void reoProfileWidthVerifyLevel( reo_plane * pPlane, int Level )
+{
+ reo_unit * pUnit;
+ for ( pUnit = pPlane->pHead; pUnit; pUnit = pUnit->Next )
+ {
+ assert( pUnit->TopRef <= Level );
+ assert( pUnit->pE->TopRef <= Level + 1 );
+ assert( pUnit->pT->TopRef <= Level + 1 );
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
diff --git a/src/bdd/reo/reoSift.c b/src/bdd/reo/reoSift.c
new file mode 100644
index 00000000..93d82f08
--- /dev/null
+++ b/src/bdd/reo/reoSift.c
@@ -0,0 +1,341 @@
+/**CFile****************************************************************
+
+ FileName [reoSift.c]
+
+ PackageName [REO: A specialized DD reordering engine.]
+
+ Synopsis [Implementation of the sifting algorihtm.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - October 15, 2002.]
+
+ Revision [$Id: reoSift.c,v 1.0 2002/15/10 03:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "reo.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Implements the variable sifting algorithm.]
+
+ Description [Performs a sequence of adjacent variable swaps known as "sifting".
+ Uses the cost functions determined by the flag.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void reoReorderSift( reo_man * p )
+{
+ double CostCurrent; // the cost of the current permutation
+ double CostLimit; // the maximum increase in cost that can be tolerated
+ double CostBest; // the best cost
+ int BestQ; // the best position
+ int VarCurrent; // the current variable to move
+ int q; // denotes the current position of the variable
+ int c; // performs the loops over variables until all of them are sifted
+ int v; // used for other purposes
+
+ assert( p->nSupp > 0 );
+
+ // set the current cost depending on the minimization criteria
+ if ( p->fMinWidth )
+ CostCurrent = p->nWidthCur;
+ else if ( p->fMinApl )
+ CostCurrent = p->nAplCur;
+ else
+ CostCurrent = p->nNodesCur;
+
+ // find the upper bound on tbe cost growth
+ CostLimit = 1 + (int)(REO_REORDER_LIMIT * CostCurrent);
+
+ // perform sifting for each of p->nSupp variables
+ for ( c = 0; c < p->nSupp; c++ )
+ {
+ // select the current variable to be the one with the largest number of nodes that is not sifted yet
+ VarCurrent = -1;
+ CostBest = -1.0;
+ for ( v = 0; v < p->nSupp; v++ )
+ {
+ p->pVarCosts[v] = REO_HIGH_VALUE;
+ if ( !p->pPlanes[v].fSifted )
+ {
+// VarCurrent = v;
+// if ( CostBest < p->pPlanes[v].statsCost )
+ if ( CostBest < p->pPlanes[v].statsNodes )
+ {
+// CostBest = p->pPlanes[v].statsCost;
+ CostBest = p->pPlanes[v].statsNodes;
+ VarCurrent = v;
+ }
+
+ }
+ }
+ assert( VarCurrent != -1 );
+ // mark this variable as sifted
+ p->pPlanes[VarCurrent].fSifted = 1;
+
+ // set the current value
+ p->pVarCosts[VarCurrent] = CostCurrent;
+
+ // set the best cost
+ CostBest = CostCurrent;
+ BestQ = VarCurrent;
+
+ // determine which way to move the variable first (up or down)
+ // the rationale is that if we move the shorter way first
+ // it is more likely that the best position will be found on the longer way
+ // and the reverse movement (to take the best position) will be faster
+ if ( VarCurrent < p->nSupp/2 ) // move up first, then down
+ {
+ // set the total cost on all levels above the current level
+ p->pPlanes[0].statsCostAbove = 0;
+ for ( v = 1; v <= VarCurrent; v++ )
+ p->pPlanes[v].statsCostAbove = p->pPlanes[v-1].statsCostAbove + p->pPlanes[v-1].statsCost;
+ // set the total cost on all levels below the current level
+ p->pPlanes[p->nSupp].statsCostBelow = 0;
+ for ( v = p->nSupp - 1; v >= VarCurrent; v-- )
+ p->pPlanes[v].statsCostBelow = p->pPlanes[v+1].statsCostBelow + p->pPlanes[v+1].statsCost;
+
+ assert( CostCurrent == p->pPlanes[VarCurrent].statsCostAbove +
+ p->pPlanes[VarCurrent].statsCost +
+ p->pPlanes[VarCurrent].statsCostBelow );
+
+ // move up
+ for ( q = VarCurrent-1; q >= 0; q-- )
+ {
+ CostCurrent -= reoReorderSwapAdjacentVars( p, q, 1 );
+ // now q points to the position of this var in the order
+ p->pVarCosts[q] = CostCurrent;
+ // update the lower bound (assuming that for level q+1 it is set correctly)
+ p->pPlanes[q].statsCostBelow = p->pPlanes[q+1].statsCostBelow + p->pPlanes[q+1].statsCost;
+ // check the upper bound
+ if ( CostCurrent >= CostLimit )
+ break;
+ // check the lower bound
+ if ( p->pPlanes[q].statsCostBelow + (REO_QUAL_PAR-1)*p->pPlanes[q].statsCostAbove/REO_QUAL_PAR >= CostBest )
+ break;
+ // update the best cost
+ if ( CostBest > CostCurrent )
+ {
+ CostBest = CostCurrent;
+ BestQ = q;
+ // adjust node limit
+ CostLimit = ddMin( CostLimit, 1 + (int)(REO_REORDER_LIMIT * CostCurrent) );
+ }
+
+ // when we are reordering for width or APL, it may happen that
+ // the number of nodes has grown above certain limit,
+ // in which case we have to resize the data structures
+ if ( p->fMinWidth || p->fMinApl )
+ {
+ if ( p->nNodesCur >= 2 * p->nNodesMaxAlloc )
+ {
+// printf( "Resizing data structures. Old size = %6d. New size = %6d.\n", p->nNodesMaxAlloc, p->nNodesCur );
+ reoResizeStructures( p, 0, p->nNodesCur, 0 );
+ }
+ }
+ }
+ // fix the plane index
+ if ( q == -1 )
+ q++;
+ // now p points to the position of this var in the order
+
+ // move down
+ for ( ; q < p->nSupp-1; )
+ {
+ CostCurrent -= reoReorderSwapAdjacentVars( p, q, 0 );
+ q++; // change q to point to the position of this var in the order
+ // sanity check: the number of nodes on the back pass should be the same
+ if ( p->pVarCosts[q] != REO_HIGH_VALUE && fabs( p->pVarCosts[q] - CostCurrent ) > REO_COST_EPSILON )
+ printf("reoReorderSift(): Error! On the backward move, the costs are different.\n");
+ p->pVarCosts[q] = CostCurrent;
+ // update the lower bound (assuming that for level q-1 it is set correctly)
+ p->pPlanes[q].statsCostAbove = p->pPlanes[q-1].statsCostAbove + p->pPlanes[q-1].statsCost;
+ // check the bounds only if the variable already reached its previous position
+ if ( q >= BestQ )
+ {
+ // check the upper bound
+ if ( CostCurrent >= CostLimit )
+ break;
+ // check the lower bound
+ if ( p->pPlanes[q].statsCostAbove + (REO_QUAL_PAR-1)*p->pPlanes[q].statsCostBelow/REO_QUAL_PAR >= CostBest )
+ break;
+ }
+ // update the best cost
+ if ( CostBest >= CostCurrent )
+ {
+ CostBest = CostCurrent;
+ BestQ = q;
+ // adjust node limit
+ CostLimit = ddMin( CostLimit, 1 + (int)(REO_REORDER_LIMIT * CostCurrent) );
+ }
+
+ // when we are reordering for width or APL, it may happen that
+ // the number of nodes has grown above certain limit,
+ // in which case we have to resize the data structures
+ if ( p->fMinWidth || p->fMinApl )
+ {
+ if ( p->nNodesCur >= 2 * p->nNodesMaxAlloc )
+ {
+// printf( "Resizing data structures. Old size = %6d. New size = %6d.\n", p->nNodesMaxAlloc, p->nNodesCur );
+ reoResizeStructures( p, 0, p->nNodesCur, 0 );
+ }
+ }
+ }
+ // move the variable up from the given position (q) to the best position (BestQ)
+ assert( q >= BestQ );
+ for ( ; q > BestQ; q-- )
+ {
+ CostCurrent -= reoReorderSwapAdjacentVars( p, q-1, 1 );
+ // sanity check: the number of nodes on the back pass should be the same
+ if ( fabs( p->pVarCosts[q-1] - CostCurrent ) > REO_COST_EPSILON )
+ {
+ printf("reoReorderSift(): Error! On the return move, the costs are different.\n" );
+ fflush(stdout);
+ }
+ }
+ }
+ else // move down first, then up
+ {
+ // set the current number of nodes on all levels above the given level
+ p->pPlanes[0].statsCostAbove = 0;
+ for ( v = 1; v <= VarCurrent; v++ )
+ p->pPlanes[v].statsCostAbove = p->pPlanes[v-1].statsCostAbove + p->pPlanes[v-1].statsCost;
+ // set the current number of nodes on all levels below the given level
+ p->pPlanes[p->nSupp].statsCostBelow = 0;
+ for ( v = p->nSupp - 1; v >= VarCurrent; v-- )
+ p->pPlanes[v].statsCostBelow = p->pPlanes[v+1].statsCostBelow + p->pPlanes[v+1].statsCost;
+
+ assert( CostCurrent == p->pPlanes[VarCurrent].statsCostAbove +
+ p->pPlanes[VarCurrent].statsCost +
+ p->pPlanes[VarCurrent].statsCostBelow );
+
+ // move down
+ for ( q = VarCurrent; q < p->nSupp-1; )
+ {
+ CostCurrent -= reoReorderSwapAdjacentVars( p, q, 0 );
+ q++; // change q to point to the position of this var in the order
+ p->pVarCosts[q] = CostCurrent;
+ // update the lower bound (assuming that for level q-1 it is set correctly)
+ p->pPlanes[q].statsCostAbove = p->pPlanes[q-1].statsCostAbove + p->pPlanes[q-1].statsCost;
+ // check the upper bound
+ if ( CostCurrent >= CostLimit )
+ break;
+ // check the lower bound
+ if ( p->pPlanes[q].statsCostAbove + (REO_QUAL_PAR-1)*p->pPlanes[q].statsCostBelow/REO_QUAL_PAR >= CostBest )
+ break;
+ // update the best cost
+ if ( CostBest > CostCurrent )
+ {
+ CostBest = CostCurrent;
+ BestQ = q;
+ // adjust node limit
+ CostLimit = ddMin( CostLimit, 1 + (int)(REO_REORDER_LIMIT * CostCurrent) );
+ }
+
+ // when we are reordering for width or APL, it may happen that
+ // the number of nodes has grown above certain limit,
+ // in which case we have to resize the data structures
+ if ( p->fMinWidth || p->fMinApl )
+ {
+ if ( p->nNodesCur >= 2 * p->nNodesMaxAlloc )
+ {
+// printf( "Resizing data structures. Old size = %6d. New size = %6d.\n", p->nNodesMaxAlloc, p->nNodesCur );
+ reoResizeStructures( p, 0, p->nNodesCur, 0 );
+ }
+ }
+ }
+
+ // move up
+ for ( --q; q >= 0; q-- )
+ {
+ CostCurrent -= reoReorderSwapAdjacentVars( p, q, 1 );
+ // now q points to the position of this var in the order
+ // sanity check: the number of nodes on the back pass should be the same
+ if ( p->pVarCosts[q] != REO_HIGH_VALUE && fabs( p->pVarCosts[q] - CostCurrent ) > REO_COST_EPSILON )
+ printf("reoReorderSift(): Error! On the backward move, the costs are different.\n");
+ p->pVarCosts[q] = CostCurrent;
+ // update the lower bound (assuming that for level q+1 it is set correctly)
+ p->pPlanes[q].statsCostBelow = p->pPlanes[q+1].statsCostBelow + p->pPlanes[q+1].statsCost;
+ // check the bounds only if the variable already reached its previous position
+ if ( q <= BestQ )
+ {
+ // check the upper bound
+ if ( CostCurrent >= CostLimit )
+ break;
+ // check the lower bound
+ if ( p->pPlanes[q].statsCostBelow + (REO_QUAL_PAR-1)*p->pPlanes[q].statsCostAbove/REO_QUAL_PAR >= CostBest )
+ break;
+ }
+ // update the best cost
+ if ( CostBest >= CostCurrent )
+ {
+ CostBest = CostCurrent;
+ BestQ = q;
+ // adjust node limit
+ CostLimit = ddMin( CostLimit, 1 + (int)(REO_REORDER_LIMIT * CostCurrent) );
+ }
+
+ // when we are reordering for width or APL, it may happen that
+ // the number of nodes has grown above certain limit,
+ // in which case we have to resize the data structures
+ if ( p->fMinWidth || p->fMinApl )
+ {
+ if ( p->nNodesCur >= 2 * p->nNodesMaxAlloc )
+ {
+// printf( "Resizing data structures. Old size = %6d. New size = %6d.\n", p->nNodesMaxAlloc, p->nNodesCur );
+ reoResizeStructures( p, 0, p->nNodesCur, 0 );
+ }
+ }
+ }
+ // fix the plane index
+ if ( q == -1 )
+ q++;
+ // now q points to the position of this var in the order
+ // move the variable down from the given position (q) to the best position (BestQ)
+ assert( q <= BestQ );
+ for ( ; q < BestQ; q++ )
+ {
+ CostCurrent -= reoReorderSwapAdjacentVars( p, q, 0 );
+ // sanity check: the number of nodes on the back pass should be the same
+ if ( fabs( p->pVarCosts[q+1] - CostCurrent ) > REO_COST_EPSILON )
+ {
+ printf("reoReorderSift(): Error! On the return move, the costs are different.\n" );
+ fflush(stdout);
+ }
+ }
+ }
+ assert( fabs( CostBest - CostCurrent ) < REO_COST_EPSILON );
+
+ // update the cost
+ if ( p->fMinWidth )
+ p->nWidthCur = (int)CostBest;
+ else if ( p->fMinApl )
+ p->nAplCur = CostCurrent;
+ else
+ p->nNodesCur = (int)CostBest;
+ }
+
+ // remove the sifted attributes if any
+ for ( v = 0; v < p->nSupp; v++ )
+ p->pPlanes[v].fSifted = 0;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
diff --git a/src/bdd/reo/reoSwap.c b/src/bdd/reo/reoSwap.c
new file mode 100644
index 00000000..cb730d8e
--- /dev/null
+++ b/src/bdd/reo/reoSwap.c
@@ -0,0 +1,898 @@
+/**CFile****************************************************************
+
+ FileName [reoSwap.c]
+
+ PackageName [REO: A specialized DD reordering engine.]
+
+ Synopsis [Implementation of the two-variable swap.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - October 15, 2002.]
+
+ Revision [$Id: reoSwap.c,v 1.0 2002/15/10 03:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "reo.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+#define AddToLinkedList( ppList, pLink ) (((pLink)->Next = *(ppList)), (*(ppList) = (pLink)))
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description [Takes the level (lev0) of the plane, which should be swapped
+ with the next plane. Returns the gain using the current cost function.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+double reoReorderSwapAdjacentVars( reo_man * p, int lev0, int fMovingUp )
+{
+ // the levels in the decision diagram
+ int lev1 = lev0 + 1, lev2 = lev0 + 2;
+ // the new nodes on lev0
+ reo_unit * pLoop, * pUnit;
+ // the new nodes on lev1
+ reo_unit * pNewPlane20, * pNewPlane21, * pNewPlane20R;
+ reo_unit * pUnitE, * pUnitER, * pUnitT;
+ // the nodes below lev1
+ reo_unit * pNew1E, * pNew1T, * pNew2E, * pNew2T;
+ reo_unit * pNew1ER, * pNew2ER;
+ // the old linked lists
+ reo_unit * pListOld0 = p->pPlanes[lev0].pHead;
+ reo_unit * pListOld1 = p->pPlanes[lev1].pHead;
+ // working planes and one more temporary plane
+ reo_unit * pListNew0 = NULL, ** ppListNew0 = &pListNew0;
+ reo_unit * pListNew1 = NULL, ** ppListNew1 = &pListNew1;
+ reo_unit * pListTemp = NULL, ** ppListTemp = &pListTemp;
+ // various integer variables
+ int fComp, fCompT, fFound, nWidthCofs, HKey, fInteract, temp, c;
+ // statistical variables
+ int nNodesUpMovedDown = 0;
+ int nNodesDownMovedUp = 0;
+ int nNodesUnrefRemoved = 0;
+ int nNodesUnrefAdded = 0;
+ int nWidthReduction = 0;
+ double AplWeightTotalLev0;
+ double AplWeightTotalLev1;
+ double AplWeightHalf;
+ double AplWeightPrev;
+ double AplWeightAfter;
+ double nCostGain;
+
+ // set the old lists
+ assert( lev0 >= 0 && lev1 < p->nSupp );
+ pListOld0 = p->pPlanes[lev0].pHead;
+ pListOld1 = p->pPlanes[lev1].pHead;
+
+ // make sure the planes have nodes
+ assert( p->pPlanes[lev0].statsNodes && p->pPlanes[lev1].statsNodes );
+ assert( pListOld0 && pListOld1 );
+
+ if ( p->fMinWidth )
+ {
+ // verify that the width parameters are set correctly
+ reoProfileWidthVerifyLevel( p->pPlanes + lev0, lev0 );
+ reoProfileWidthVerifyLevel( p->pPlanes + lev1, lev1 );
+ // start the storage for cofactors
+ nWidthCofs = 0;
+ }
+ else if ( p->fMinApl )
+ {
+ AplWeightPrev = p->nAplCur;
+ AplWeightAfter = p->nAplCur;
+ AplWeightTotalLev0 = 0.0;
+ AplWeightTotalLev1 = 0.0;
+ }
+
+ // check if the planes interact
+ fInteract = 0; // assume that they do not interact
+ for ( pUnit = pListOld0; pUnit; pUnit = pUnit->Next )
+ {
+ if ( pUnit->pT->lev == lev1 || Unit_Regular(pUnit->pE)->lev == lev1 )
+ {
+ fInteract = 1;
+ break;
+ }
+ // change the level now, this is done for efficiency reasons
+ pUnit->lev = lev1;
+ }
+
+ // set the new signature for hashing
+ p->nSwaps++;
+ if ( !fInteract )
+// if ( 0 )
+ {
+ // perform the swap without interaction
+ p->nNISwaps++;
+
+ // change the levels
+ if ( p->fMinWidth )
+ {
+ // go through the current lower level, which will become upper
+ for ( pUnit = pListOld1; pUnit; pUnit = pUnit->Next )
+ {
+ pUnit->lev = lev0;
+
+ pUnitER = Unit_Regular(pUnit->pE);
+ if ( pUnitER->TopRef > lev0 )
+ {
+ if ( pUnitER->Sign != p->nSwaps )
+ {
+ if ( pUnitER->TopRef == lev2 )
+ {
+ pUnitER->TopRef = lev1;
+ nWidthReduction--;
+ }
+ else
+ {
+ assert( pUnitER->TopRef == lev1 );
+ }
+ pUnitER->Sign = p->nSwaps;
+ }
+ }
+
+ pUnitT = pUnit->pT;
+ if ( pUnitT->TopRef > lev0 )
+ {
+ if ( pUnitT->Sign != p->nSwaps )
+ {
+ if ( pUnitT->TopRef == lev2 )
+ {
+ pUnitT->TopRef = lev1;
+ nWidthReduction--;
+ }
+ else
+ {
+ assert( pUnitT->TopRef == lev1 );
+ }
+ pUnitT->Sign = p->nSwaps;
+ }
+ }
+
+ }
+
+ // go through the current upper level, which will become lower
+ for ( pUnit = pListOld0; pUnit; pUnit = pUnit->Next )
+ {
+ pUnit->lev = lev1;
+
+ pUnitER = Unit_Regular(pUnit->pE);
+ if ( pUnitER->TopRef > lev0 )
+ {
+ if ( pUnitER->Sign != p->nSwaps )
+ {
+ assert( pUnitER->TopRef == lev1 );
+ pUnitER->TopRef = lev2;
+ pUnitER->Sign = p->nSwaps;
+ nWidthReduction++;
+ }
+ }
+
+ pUnitT = pUnit->pT;
+ if ( pUnitT->TopRef > lev0 )
+ {
+ if ( pUnitT->Sign != p->nSwaps )
+ {
+ assert( pUnitT->TopRef == lev1 );
+ pUnitT->TopRef = lev2;
+ pUnitT->Sign = p->nSwaps;
+ nWidthReduction++;
+ }
+ }
+ }
+ }
+ else
+ {
+// for ( pUnit = pListOld0; pUnit; pUnit = pUnit->Next )
+// pUnit->lev = lev1;
+ for ( pUnit = pListOld1; pUnit; pUnit = pUnit->Next )
+ pUnit->lev = lev0;
+ }
+
+ // set the new linked lists, which will be attached to the planes
+ pListNew0 = pListOld1;
+ pListNew1 = pListOld0;
+
+ if ( p->fMinApl )
+ {
+ AplWeightTotalLev0 = p->pPlanes[lev1].statsCost;
+ AplWeightTotalLev1 = p->pPlanes[lev0].statsCost;
+ }
+
+ // set the changes in terms of nodes
+ nNodesUpMovedDown = p->pPlanes[lev0].statsNodes;
+ nNodesDownMovedUp = p->pPlanes[lev1].statsNodes;
+ goto finish;
+ }
+ p->Signature++;
+
+
+ // two-variable swap is done in three easy steps
+ // previously I thought that steps (1) and (2) can be merged into one step
+ // now it is clear that this cannot be done without changing a lot of other stuff...
+
+ // (1) walk through the upper level, find units without cofactors in the lower level
+ // and move them to the new lower level (while adding to the cache)
+ // (2) walk through the uppoer level, and tranform all the remaning nodes
+ // while employing cache for the new lower level
+ // (3) walk through the old lower level, find those nodes whose ref counters are not zero,
+ // and move them to the new uppoer level, free other nodes
+
+ // (1) walk through the upper level, find units without cofactors in the lower level
+ // and move them to the new lower level (while adding to the cache)
+ for ( pLoop = pListOld0; pLoop; )
+ {
+ pUnit = pLoop;
+ pLoop = pLoop->Next;
+
+ pUnitE = pUnit->pE;
+ pUnitER = Unit_Regular(pUnitE);
+ pUnitT = pUnit->pT;
+
+ if ( pUnitER->lev != lev1 && pUnitT->lev != lev1 )
+ {
+ // before after
+ //
+ // <p1>
+ // 0 / \ 1
+ // / \
+ // / \
+ // / \ <p2n>
+ // / \ 0 / \ 1
+ // / \ / \
+ // / \ / \
+ // F0 F1 F0 F1
+
+ // move to plane-2-new
+ // nothing changes in the process (cofactors, ref counter, APL weight)
+ pUnit->lev = lev1;
+ AddToLinkedList( ppListNew1, pUnit );
+ if ( p->fMinApl )
+ AplWeightTotalLev1 += pUnit->Weight;
+
+ // add to cache - find the cell with different signature (not the current one!)
+ for ( HKey = hashKey3(p->Signature, pUnitE, pUnitT, p->nTableSize);
+ p->HTable[HKey].Sign == p->Signature;
+ HKey = (HKey+1) % p->nTableSize );
+ assert( p->HTable[HKey].Sign != p->Signature );
+ p->HTable[HKey].Sign = p->Signature;
+ p->HTable[HKey].Arg1 = (unsigned)pUnitE;
+ p->HTable[HKey].Arg2 = (unsigned)pUnitT;
+ p->HTable[HKey].Arg3 = (unsigned)pUnit;
+
+ nNodesUpMovedDown++;
+
+ if ( p->fMinWidth )
+ {
+ // update the cofactors's top ref
+ if ( pUnitER->TopRef > lev0 ) // the cofactor's top ref level is one of the current two levels
+ {
+ assert( pUnitER->TopRef == lev1 );
+ pUnitER->TopRefNew = lev2;
+ if ( pUnitER->Sign != p->nSwaps )
+ {
+ pUnitER->Sign = p->nSwaps; // set the current signature
+ p->pWidthCofs[ nWidthCofs++ ] = pUnitER;
+ }
+ }
+ if ( pUnitT->TopRef > lev0 ) // the cofactor's top ref level is one of the current two levels
+ {
+ assert( pUnitT->TopRef == lev1 );
+ pUnitT->TopRefNew = lev2;
+ if ( pUnitT->Sign != p->nSwaps )
+ {
+ pUnitT->Sign = p->nSwaps; // set the current signature
+ p->pWidthCofs[ nWidthCofs++ ] = pUnitT;
+ }
+ }
+ }
+ }
+ else
+ {
+ // add to the temporary plane
+ AddToLinkedList( ppListTemp, pUnit );
+ }
+ }
+
+
+ // (2) walk through the uppoer level, and tranform all the remaning nodes
+ // while employing cache for the new lower level
+ for ( pLoop = pListTemp; pLoop; )
+ {
+ pUnit = pLoop;
+ pLoop = pLoop->Next;
+
+ pUnitE = pUnit->pE;
+ pUnitER = Unit_Regular(pUnitE);
+ pUnitT = pUnit->pT;
+ fComp = (int)(pUnitER != pUnitE);
+
+ // count the amount of weight to reduce the APL of the children of this node
+ if ( p->fMinApl )
+ AplWeightHalf = 0.5 * pUnit->Weight;
+
+ // determine what situation is this
+ if ( pUnitER->lev == lev1 && pUnitT->lev == lev1 )
+ {
+ if ( fComp == 0 )
+ {
+ // before after
+ //
+ // <p1> <p1n>
+ // 0 / \ 1 0 / \ 1
+ // / \ / \
+ // / \ / \
+ // <p2> <p2> <p2n> <p2n>
+ // 0 / \ 1 0 / \ 1 0 / \ 1 0 / \ 1
+ // / \ / \ / \ / \
+ // / \ / \ / \ / \
+ // F0 F1 F2 F3 F0 F2 F1 F3
+ // pNew1E pNew1T pNew2E pNew2T
+ //
+ pNew1E = pUnitE->pE; // F0
+ pNew1T = pUnitT->pE; // F2
+
+ pNew2E = pUnitE->pT; // F1
+ pNew2T = pUnitT->pT; // F3
+ }
+ else
+ {
+ // before after
+ //
+ // <p1> <p1n>
+ // 0 . \ 1 0 / \ 1
+ // . \ / \
+ // . \ / \
+ // <p2> <p2> <p2n> <p2n>
+ // 0 / \ 1 0 / \ 1 0 . \ 1 0 . \ 1
+ // / \ / \ . \ . \
+ // / \ / \ . \ . \
+ // F0 F1 F2 F3 F0 F2 F1 F3
+ // pNew1E pNew1T pNew2E pNew2T
+ //
+ pNew1E = Unit_Not(pUnitER->pE); // F0
+ pNew1T = pUnitT->pE; // F2
+
+ pNew2E = Unit_Not(pUnitER->pT); // F1
+ pNew2T = pUnitT->pT; // F3
+ }
+ // subtract ref counters - on the level P2
+ pUnitER->n--;
+ pUnitT->n--;
+
+ // mark the change in the APL weights
+ if ( p->fMinApl )
+ {
+ pUnitER->Weight -= AplWeightHalf;
+ pUnitT->Weight -= AplWeightHalf;
+ AplWeightAfter -= pUnit->Weight;
+ }
+ }
+ else if ( pUnitER->lev == lev1 )
+ {
+ if ( fComp == 0 )
+ {
+ // before after
+ //
+ // <p1> <p1n>
+ // 0 / \ 1 0 / \ 1
+ // / \ / \
+ // / \ / \
+ // <p2> \ <p2n> <p2n>
+ // 0 / \ 1 \ 0 / \ 1 0 / \ 1
+ // / \ \ / \ / \
+ // / \ \ / \ / \
+ // F0 F1 F3 F0 F3 F1 F3
+ // pNew1E pNew1T pNew2E pNew2T
+ //
+ pNew1E = pUnitER->pE; // F0
+ pNew1T = pUnitT; // F3
+
+ pNew2E = pUnitER->pT; // F1
+ pNew2T = pUnitT; // F3
+ }
+ else
+ {
+ // before after
+ //
+ // <p1> <p1n>
+ // 0 . \ 1 0 / \ 1
+ // . \ / \
+ // . \ / \
+ // <p2> \ <p2n> <p2n>
+ // 0 / \ 1 \ 0 . \ 1 0 . \ 1
+ // / \ \ . \ . \
+ // / \ \ . \ . \
+ // F0 F1 F3 F0 F3 F1 F3
+ // pNew1E pNew1T pNew2E pNew2T
+ //
+ pNew1E = Unit_Not(pUnitER->pE); // F0
+ pNew1T = pUnitT; // F3
+
+ pNew2E = Unit_Not(pUnitER->pT); // F1
+ pNew2T = pUnitT; // F3
+ }
+ // subtract ref counter - on the level P2
+ pUnitER->n--;
+ // subtract ref counter - on other levels
+ pUnitT->n--; ///
+
+ // mark the change in the APL weights
+ if ( p->fMinApl )
+ {
+ pUnitER->Weight -= AplWeightHalf;
+ AplWeightAfter -= AplWeightHalf;
+ }
+ }
+ else if ( pUnitT->lev == lev1 )
+ {
+ // before after
+ //
+ // <p1> <p1n>
+ // 0 / \ 1 0 / \ 1
+ // / \ / \
+ // / \ / \
+ // / <p2> <p2n> <p2n>
+ // / 0 / \ 1 0 / \ 1 0 / \ 1
+ // / / \ / \ / \
+ // / / \ / \ / \
+ // F0 F2 F3 F0 F2 F0 F3
+ // pNew1E pNew1T pNew2E pNew2T
+ //
+ pNew1E = pUnitE; // F0
+ pNew1T = pUnitT->pE; // F2
+
+ pNew2E = pUnitE; // F0
+ pNew2T = pUnitT->pT; // F3
+
+ // subtract incoming edge counter - on the level P2
+ pUnitT->n--;
+ // subtract ref counter - on other levels
+ pUnitER->n--; ///
+
+ // mark the change in the APL weights
+ if ( p->fMinApl )
+ {
+ pUnitT->Weight -= AplWeightHalf;
+ AplWeightAfter -= AplWeightHalf;
+ }
+ }
+ else
+ {
+ assert( 0 ); // should never happen
+ }
+
+
+ // consider all the cases except the last one
+ if ( pNew1E == pNew1T )
+ {
+ pNewPlane20 = pNew1T;
+
+ if ( p->fMinWidth )
+ {
+ // update the cofactors's top ref
+ if ( pNew1T->TopRef > lev0 ) // the cofactor's top ref level is one of the current two levels
+ {
+ pNew1T->TopRefNew = lev1;
+ if ( pNew1T->Sign != p->nSwaps )
+ {
+ pNew1T->Sign = p->nSwaps; // set the current signature
+ p->pWidthCofs[ nWidthCofs++ ] = pNew1T;
+ }
+ }
+ }
+ }
+ else
+ {
+ // pNew1T can be complemented
+ fCompT = Cudd_IsComplement(pNew1T);
+ if ( fCompT )
+ {
+ pNew1E = Unit_Not(pNew1E);
+ pNew1T = Unit_Not(pNew1T);
+ }
+
+ // check the hash-table
+ fFound = 0;
+ for ( HKey = hashKey3(p->Signature, pNew1E, pNew1T, p->nTableSize);
+ p->HTable[HKey].Sign == p->Signature;
+ HKey = (HKey+1) % p->nTableSize )
+ if ( p->HTable[HKey].Arg1 == (unsigned)pNew1E && p->HTable[HKey].Arg2 == (unsigned)pNew1T )
+ { // the entry is present
+ // assign this entry
+ pNewPlane20 = (reo_unit *)p->HTable[HKey].Arg3;
+ assert( pNewPlane20->lev == lev1 );
+ fFound = 1;
+ p->HashSuccess++;
+ break;
+ }
+
+ if ( !fFound )
+ { // create the new entry
+ pNewPlane20 = reoUnitsGetNextUnit( p ); // increments the unit counter
+ pNewPlane20->pE = pNew1E;
+ pNewPlane20->pT = pNew1T;
+ pNewPlane20->n = 0; // ref will be added later
+ pNewPlane20->lev = lev1;
+ if ( p->fMinWidth )
+ {
+ pNewPlane20->TopRef = lev1;
+ pNewPlane20->Sign = 0;
+ }
+ // set the weight of this node
+ if ( p->fMinApl )
+ pNewPlane20->Weight = 0.0;
+
+ // increment ref counters of children
+ pNew1ER = Unit_Regular(pNew1E);
+ pNew1ER->n++; //
+ pNew1T->n++; //
+
+ // insert into the data structure
+ AddToLinkedList( ppListNew1, pNewPlane20 );
+
+ // add this entry to cache
+ assert( p->HTable[HKey].Sign != p->Signature );
+ p->HTable[HKey].Sign = p->Signature;
+ p->HTable[HKey].Arg1 = (unsigned)pNew1E;
+ p->HTable[HKey].Arg2 = (unsigned)pNew1T;
+ p->HTable[HKey].Arg3 = (unsigned)pNewPlane20;
+
+ nNodesUnrefAdded++;
+
+ if ( p->fMinWidth )
+ {
+ // update the cofactors's top ref
+ if ( pNew1ER->TopRef > lev0 ) // the cofactor's top ref level is one of the current two levels
+ {
+ if ( pNew1ER->Sign != p->nSwaps )
+ {
+ pNew1ER->TopRefNew = lev2;
+ if ( pNew1ER->Sign != p->nSwaps )
+ {
+ pNew1ER->Sign = p->nSwaps; // set the current signature
+ p->pWidthCofs[ nWidthCofs++ ] = pNew1ER;
+ }
+ }
+ // otherwise the level is already set correctly
+ else
+ {
+ assert( pNew1ER->TopRefNew == lev1 || pNew1ER->TopRefNew == lev2 );
+ }
+ }
+ // update the cofactors's top ref
+ if ( pNew1T->TopRef > lev0 ) // the cofactor's top ref level is one of the current two levels
+ {
+ if ( pNew1T->Sign != p->nSwaps )
+ {
+ pNew1T->TopRefNew = lev2;
+ if ( pNew1T->Sign != p->nSwaps )
+ {
+ pNew1T->Sign = p->nSwaps; // set the current signature
+ p->pWidthCofs[ nWidthCofs++ ] = pNew1T;
+ }
+ }
+ // otherwise the level is already set correctly
+ else
+ {
+ assert( pNew1T->TopRefNew == lev1 || pNew1T->TopRefNew == lev2 );
+ }
+ }
+ }
+ }
+
+ if ( p->fMinApl )
+ {
+ // increment the weight of this node
+ pNewPlane20->Weight += AplWeightHalf;
+ // mark the change in the APL weight
+ AplWeightAfter += AplWeightHalf;
+ // update the total weight of this level
+ AplWeightTotalLev1 += AplWeightHalf;
+ }
+
+ if ( fCompT )
+ pNewPlane20 = Unit_Not(pNewPlane20);
+ }
+
+ if ( pNew2E == pNew2T )
+ {
+ pNewPlane21 = pNew2T;
+
+ if ( p->fMinWidth )
+ {
+ // update the cofactors's top ref
+ if ( pNew2T->TopRef > lev0 ) // the cofactor's top ref level is one of the current two levels
+ {
+ pNew2T->TopRefNew = lev1;
+ if ( pNew2T->Sign != p->nSwaps )
+ {
+ pNew2T->Sign = p->nSwaps; // set the current signature
+ p->pWidthCofs[ nWidthCofs++ ] = pNew2T;
+ }
+ }
+ }
+ }
+ else
+ {
+ assert( !Cudd_IsComplement(pNew2T) );
+
+ // check the hash-table
+ fFound = 0;
+ for ( HKey = hashKey3(p->Signature, pNew2E, pNew2T, p->nTableSize);
+ p->HTable[HKey].Sign == p->Signature;
+ HKey = (HKey+1) % p->nTableSize )
+ if ( p->HTable[HKey].Arg1 == (unsigned)pNew2E && p->HTable[HKey].Arg2 == (unsigned)pNew2T )
+ { // the entry is present
+ // assign this entry
+ pNewPlane21 = (reo_unit *)p->HTable[HKey].Arg3;
+ assert( pNewPlane21->lev == lev1 );
+ fFound = 1;
+ p->HashSuccess++;
+ break;
+ }
+
+ if ( !fFound )
+ { // create the new entry
+ pNewPlane21 = reoUnitsGetNextUnit( p ); // increments the unit counter
+ pNewPlane21->pE = pNew2E;
+ pNewPlane21->pT = pNew2T;
+ pNewPlane21->n = 0; // ref will be added later
+ pNewPlane21->lev = lev1;
+ if ( p->fMinWidth )
+ {
+ pNewPlane21->TopRef = lev1;
+ pNewPlane21->Sign = 0;
+ }
+ // set the weight of this node
+ if ( p->fMinApl )
+ pNewPlane21->Weight = 0.0;
+
+ // increment ref counters of children
+ pNew2ER = Unit_Regular(pNew2E);
+ pNew2ER->n++; //
+ pNew2T->n++; //
+
+ // insert into the data structure
+// reoUnitsAddUnitToPlane( &P2new, pNewPlane21 );
+ AddToLinkedList( ppListNew1, pNewPlane21 );
+
+ // add this entry to cache
+ assert( p->HTable[HKey].Sign != p->Signature );
+ p->HTable[HKey].Sign = p->Signature;
+ p->HTable[HKey].Arg1 = (unsigned)pNew2E;
+ p->HTable[HKey].Arg2 = (unsigned)pNew2T;
+ p->HTable[HKey].Arg3 = (unsigned)pNewPlane21;
+
+ nNodesUnrefAdded++;
+
+
+ if ( p->fMinWidth )
+ {
+ // update the cofactors's top ref
+ if ( pNew2ER->TopRef > lev0 ) // the cofactor's top ref level is one of the current two levels
+ {
+ if ( pNew2ER->Sign != p->nSwaps )
+ {
+ pNew2ER->TopRefNew = lev2;
+ if ( pNew2ER->Sign != p->nSwaps )
+ {
+ pNew2ER->Sign = p->nSwaps; // set the current signature
+ p->pWidthCofs[ nWidthCofs++ ] = pNew2ER;
+ }
+ }
+ // otherwise the level is already set correctly
+ else
+ {
+ assert( pNew2ER->TopRefNew == lev1 || pNew2ER->TopRefNew == lev2 );
+ }
+ }
+ // update the cofactors's top ref
+ if ( pNew2T->TopRef > lev0 ) // the cofactor's top ref level is one of the current two levels
+ {
+ if ( pNew2T->Sign != p->nSwaps )
+ {
+ pNew2T->TopRefNew = lev2;
+ if ( pNew2T->Sign != p->nSwaps )
+ {
+ pNew2T->Sign = p->nSwaps; // set the current signature
+ p->pWidthCofs[ nWidthCofs++ ] = pNew2T;
+ }
+ }
+ // otherwise the level is already set correctly
+ else
+ {
+ assert( pNew2T->TopRefNew == lev1 || pNew2T->TopRefNew == lev2 );
+ }
+ }
+ }
+ }
+
+ if ( p->fMinApl )
+ {
+ // increment the weight of this node
+ pNewPlane21->Weight += AplWeightHalf;
+ // mark the change in the APL weight
+ AplWeightAfter += AplWeightHalf;
+ // update the total weight of this level
+ AplWeightTotalLev1 += AplWeightHalf;
+ }
+ }
+ // in all cases, the node will be added to the plane-1
+ // this should be the same node (pUnit) as was originally there
+ // because it is referenced by the above nodes
+
+ assert( !Cudd_IsComplement(pNewPlane21) );
+ // should be the case; otherwise reordering is not a local operation
+
+ pUnit->pE = pNewPlane20;
+ pUnit->pT = pNewPlane21;
+ assert( pUnit->lev == lev0 );
+ // reference counter remains the same; the APL weight remains the same
+
+ // increment ref counters of children
+ pNewPlane20R = Unit_Regular(pNewPlane20);
+ pNewPlane20R->n++; ///
+ pNewPlane21->n++; ///
+
+ // insert into the data structure
+ AddToLinkedList( ppListNew0, pUnit );
+ if ( p->fMinApl )
+ AplWeightTotalLev0 += pUnit->Weight;
+ }
+
+ // (3) walk through the old lower level, find those nodes whose ref counters are not zero,
+ // and move them to the new uppoer level, free other nodes
+ for ( pLoop = pListOld1; pLoop; )
+ {
+ pUnit = pLoop;
+ pLoop = pLoop->Next;
+ if ( pUnit->n )
+ {
+ assert( !p->fMinApl || pUnit->Weight > 0.0 );
+ // the node should be added to the new level
+ // no need to check the hash table
+ pUnit->lev = lev0;
+ AddToLinkedList( ppListNew0, pUnit );
+ if ( p->fMinApl )
+ AplWeightTotalLev0 += pUnit->Weight;
+
+ nNodesDownMovedUp++;
+
+ if ( p->fMinWidth )
+ {
+ pUnitER = Unit_Regular(pUnit->pE);
+ pUnitT = pUnit->pT;
+
+ // update the cofactors's top ref
+ if ( pUnitER->TopRef > lev0 ) // the cofactor's top ref level is one of the current two levels
+ {
+ pUnitER->TopRefNew = lev1;
+ if ( pUnitER->Sign != p->nSwaps )
+ {
+ pUnitER->Sign = p->nSwaps; // set the current signature
+ p->pWidthCofs[ nWidthCofs++ ] = pUnitER;
+ }
+ }
+ if ( pUnitT->TopRef > lev0 ) // the cofactor's top ref level is one of the current two levels
+ {
+ pUnitT->TopRefNew = lev1;
+ if ( pUnitT->Sign != p->nSwaps )
+ {
+ pUnitT->Sign = p->nSwaps; // set the current signature
+ p->pWidthCofs[ nWidthCofs++ ] = pUnitT;
+ }
+ }
+ }
+ }
+ else
+ {
+ assert( !p->fMinApl || pUnit->Weight == 0.0 );
+ // decrement reference counters of children
+ pUnitER = Unit_Regular(pUnit->pE);
+ pUnitT = pUnit->pT;
+ pUnitER->n--; ///
+ pUnitT->n--; ///
+ // the node should be thrown away
+ reoUnitsRecycleUnit( p, pUnit );
+ nNodesUnrefRemoved++;
+ }
+ }
+
+finish:
+
+ // attach the new levels to the planes
+ p->pPlanes[lev0].pHead = pListNew0;
+ p->pPlanes[lev1].pHead = pListNew1;
+
+ // swap the sift status
+ temp = p->pPlanes[lev0].fSifted;
+ p->pPlanes[lev0].fSifted = p->pPlanes[lev1].fSifted;
+ p->pPlanes[lev1].fSifted = temp;
+
+ // swap variables in the variable map
+ if ( p->pOrderInt )
+ {
+ temp = p->pOrderInt[lev0];
+ p->pOrderInt[lev0] = p->pOrderInt[lev1];
+ p->pOrderInt[lev1] = temp;
+ }
+
+ // adjust the node profile
+ p->pPlanes[lev0].statsNodes -= (nNodesUpMovedDown - nNodesDownMovedUp);
+ p->pPlanes[lev1].statsNodes -= (nNodesDownMovedUp - nNodesUpMovedDown) + nNodesUnrefRemoved - nNodesUnrefAdded;
+ p->nNodesCur -= nNodesUnrefRemoved - nNodesUnrefAdded;
+
+ // adjust the node profile on this level
+ if ( p->fMinWidth )
+ {
+ for ( c = 0; c < nWidthCofs; c++ )
+ {
+ if ( p->pWidthCofs[c]->TopRefNew < p->pWidthCofs[c]->TopRef )
+ {
+ p->pWidthCofs[c]->TopRef = p->pWidthCofs[c]->TopRefNew;
+ nWidthReduction--;
+ }
+ else if ( p->pWidthCofs[c]->TopRefNew > p->pWidthCofs[c]->TopRef )
+ {
+ p->pWidthCofs[c]->TopRef = p->pWidthCofs[c]->TopRefNew;
+ nWidthReduction++;
+ }
+ }
+ // verify that the profile is okay
+ reoProfileWidthVerifyLevel( p->pPlanes + lev0, lev0 );
+ reoProfileWidthVerifyLevel( p->pPlanes + lev1, lev1 );
+
+ // compute the total gain in terms of width
+ nCostGain = (nNodesDownMovedUp - nNodesUpMovedDown + nNodesUnrefRemoved - nNodesUnrefAdded) + nWidthReduction;
+ // adjust the width on this level
+ p->pPlanes[lev1].statsWidth -= (int)nCostGain;
+ // set the cost
+ p->pPlanes[lev1].statsCost = p->pPlanes[lev1].statsWidth;
+ }
+ else if ( p->fMinApl )
+ {
+ // compute the total gain in terms of APL
+ nCostGain = AplWeightPrev - AplWeightAfter;
+ // make sure that the ALP is updated correctly
+// assert( p->pPlanes[lev0].statsCost + p->pPlanes[lev1].statsCost - nCostGain ==
+// AplWeightTotalLev0 + AplWeightTotalLev1 );
+ // adjust the profile
+ p->pPlanes[lev0].statsApl = AplWeightTotalLev0;
+ p->pPlanes[lev1].statsApl = AplWeightTotalLev1;
+ // set the cost
+ p->pPlanes[lev0].statsCost = p->pPlanes[lev0].statsApl;
+ p->pPlanes[lev1].statsCost = p->pPlanes[lev1].statsApl;
+ }
+ else
+ {
+ // compute the total gain in terms of the number of nodes
+ nCostGain = nNodesUnrefRemoved - nNodesUnrefAdded;
+ // adjust the profile (adjusted above)
+ // set the cost
+ p->pPlanes[lev0].statsCost = p->pPlanes[lev0].statsNodes;
+ p->pPlanes[lev1].statsCost = p->pPlanes[lev1].statsNodes;
+ }
+
+ return nCostGain;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
diff --git a/src/bdd/reo/reoTest.c b/src/bdd/reo/reoTest.c
new file mode 100644
index 00000000..82f3d5f5
--- /dev/null
+++ b/src/bdd/reo/reoTest.c
@@ -0,0 +1,251 @@
+/**CFile****************************************************************
+
+ FileName [reoTest.c]
+
+ PackageName [REO: A specialized DD reordering engine.]
+
+ Synopsis [Various testing procedures (may be outdated).]
+
+ Author [Alan Mishchenko <alanmi@ece.pdx.edu>]
+
+ Affiliation [ECE Department. Portland State University, Portland, Oregon.]
+
+ Date [Ver. 1.0. Started - October 15, 2002.]
+
+ Revision [$Id: reoTest.c,v 1.0 2002/15/10 03:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "reo.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Reorders the DD using REO and CUDD.]
+
+ Description [This function can be used to test the performance of the reordering package.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_ReorderTest( DdManager * dd, DdNode * Func )
+{
+ reo_man * pReo;
+ DdNode * Temp, * Temp1;
+ int pOrder[1000];
+
+ pReo = Extra_ReorderInit( 100, 100 );
+
+//Extra_DumpDot( dd, &Func, 1, "beforReo.dot", 0 );
+ Temp = Extra_Reorder( pReo, dd, Func, pOrder ); Cudd_Ref( Temp );
+//Extra_DumpDot( dd, &Temp, 1, "afterReo.dot", 0 );
+
+ Temp1 = Extra_ReorderCudd(dd, Func, NULL ); Cudd_Ref( Temp1 );
+printf( "Initial = %d. Final = %d. Cudd = %d.\n", Cudd_DagSize(Func), Cudd_DagSize(Temp), Cudd_DagSize(Temp1) );
+ Cudd_RecursiveDeref( dd, Temp1 );
+ Cudd_RecursiveDeref( dd, Temp );
+
+ Extra_ReorderQuit( pReo );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Reorders the DD using REO and CUDD.]
+
+ Description [This function can be used to test the performance of the reordering package.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Extra_ReorderTestArray( DdManager * dd, DdNode * Funcs[], int nFuncs )
+{
+ reo_man * pReo;
+ DdNode * FuncsRes[1000];
+ int pOrder[1000];
+ int i;
+
+ pReo = Extra_ReorderInit( 100, 100 );
+ Extra_ReorderArray( pReo, dd, Funcs, FuncsRes, nFuncs, pOrder );
+ Extra_ReorderQuit( pReo );
+
+printf( "Initial = %d. Final = %d.\n", Cudd_SharingSize(Funcs,nFuncs), Cudd_SharingSize(FuncsRes,nFuncs) );
+
+ for ( i = 0; i < nFuncs; i++ )
+ Cudd_RecursiveDeref( dd, FuncsRes[i] );
+
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reorders the DD using CUDD package.]
+
+ Description [Transfers the DD into a temporary manager in such a way
+ that the level correspondence is preserved. Reorders the manager
+ and transfers the DD back into the original manager using the topmost
+ levels of the manager, in such a way that the ordering of levels is
+ preserved. The resulting permutation is returned in the array
+ given by the user.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdNode * Extra_ReorderCudd( DdManager * dd, DdNode * aFunc, int pPermuteReo[] )
+{
+ static DdManager * ddReorder = NULL;
+ static int * Permute = NULL;
+ static int * PermuteReo1 = NULL;
+ static int * PermuteReo2 = NULL;
+ DdNode * aFuncReorder, * aFuncNew;
+ int lev, var;
+
+ // start the reordering manager
+ if ( ddReorder == NULL )
+ {
+ Permute = ALLOC( int, dd->size );
+ PermuteReo1 = ALLOC( int, dd->size );
+ PermuteReo2 = ALLOC( int, dd->size );
+ ddReorder = Cudd_Init( dd->size, 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 );
+ Cudd_AutodynDisable(ddReorder);
+ }
+
+ // determine the permutation of variable to make sure that var order in bFunc
+ // will not change when this function is transfered into the new manager
+ for ( lev = 0; lev < dd->size; lev++ )
+ {
+ Permute[ dd->invperm[lev] ] = ddReorder->invperm[lev];
+ PermuteReo1[ ddReorder->invperm[lev] ] = dd->invperm[lev];
+ }
+ // transfer this function into the new manager in such a way that ordering of vars does not change
+ aFuncReorder = Extra_TransferPermute( dd, ddReorder, aFunc, Permute ); Cudd_Ref( aFuncReorder );
+// assert( Cudd_DagSize(aFunc) == Cudd_DagSize(aFuncReorder) );
+
+ // perform the reordering
+printf( "Nodes before = %d.\n", Cudd_DagSize(aFuncReorder) );
+ Cudd_ReduceHeap( ddReorder, CUDD_REORDER_SYMM_SIFT, 1 );
+printf( "Nodes before = %d.\n", Cudd_DagSize(aFuncReorder) );
+
+ // determine the reverse variable permutation
+ for ( lev = 0; lev < dd->size; lev++ )
+ {
+ Permute[ ddReorder->invperm[lev] ] = dd->invperm[lev];
+ PermuteReo2[ dd->invperm[lev] ] = ddReorder->invperm[lev];
+ }
+
+ // transfer this function into the new manager in such a way that ordering of vars does not change
+ aFuncNew = Extra_TransferPermute( ddReorder, dd, aFuncReorder, Permute ); Cudd_Ref( aFuncNew );
+// assert( Cudd_DagSize(aFuncNew) == Cudd_DagSize(aFuncReorder) );
+ Cudd_RecursiveDeref( ddReorder, aFuncReorder );
+
+ // derive the resulting variable ordering
+ if ( pPermuteReo )
+ for ( var = 0; var < dd->size; var++ )
+ pPermuteReo[var] = PermuteReo1[ PermuteReo2[var] ];
+
+ Cudd_Deref( aFuncNew );
+ return aFuncNew;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description [Transfers the BDD into another manager minimizes it and
+ returns the min number of nodes; disposes of the BDD in the new manager.
+ Useful for debugging or comparing the performance of other reordering
+ procedures.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Extra_bddReorderTest( DdManager * dd, DdNode * bF )
+{
+ static DdManager * s_ddmin;
+ DdNode * bFmin;
+ int nNodes;
+// int clk1;
+
+ if ( s_ddmin == NULL )
+ s_ddmin = Cudd_Init( dd->size, 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0);
+
+// Cudd_ShuffleHeap( s_ddmin, dd->invperm );
+
+// clk1 = clock();
+ bFmin = Cudd_bddTransfer( dd, s_ddmin, bF ); Cudd_Ref( bFmin );
+ Cudd_ReduceHeap(s_ddmin,CUDD_REORDER_SIFT,1);
+// Cudd_ReduceHeap(s_ddmin,CUDD_REORDER_SYMM_SIFT,1);
+ nNodes = Cudd_DagSize( bFmin );
+ Cudd_RecursiveDeref( s_ddmin, bFmin );
+
+// printf( "Classical variable reordering time = %.2f sec\n", (float)(clock() - clk1)/(float)(CLOCKS_PER_SEC) );
+ return nNodes;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description [Transfers the ADD into another manager minimizes it and
+ returns the min number of nodes; disposes of the BDD in the new manager.
+ Useful for debugging or comparing the performance of other reordering
+ procedures.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Extra_addReorderTest( DdManager * dd, DdNode * aF )
+{
+ static DdManager * s_ddmin;
+ DdNode * bF;
+ DdNode * bFmin;
+ DdNode * aFmin;
+ int nNodesBeg;
+ int nNodesEnd;
+ int clk1;
+
+ if ( s_ddmin == NULL )
+ s_ddmin = Cudd_Init( dd->size, 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0);
+
+// Cudd_ShuffleHeap( s_ddmin, dd->invperm );
+
+ clk1 = clock();
+ bF = Cudd_addBddPattern( dd, aF ); Cudd_Ref( bF );
+ bFmin = Cudd_bddTransfer( dd, s_ddmin, bF ); Cudd_Ref( bFmin );
+ Cudd_RecursiveDeref( dd, bF );
+ aFmin = Cudd_BddToAdd( s_ddmin, bFmin ); Cudd_Ref( aFmin );
+ Cudd_RecursiveDeref( s_ddmin, bFmin );
+
+ nNodesBeg = Cudd_DagSize( aFmin );
+ Cudd_ReduceHeap(s_ddmin,CUDD_REORDER_SIFT,1);
+// Cudd_ReduceHeap(s_ddmin,CUDD_REORDER_SYMM_SIFT,1);
+ nNodesEnd = Cudd_DagSize( aFmin );
+ Cudd_RecursiveDeref( s_ddmin, aFmin );
+
+ printf( "Classical reordering of ADDs: Before = %d. After = %d.\n", nNodesBeg, nNodesEnd );
+ printf( "Classical variable reordering time = %.2f sec\n", (float)(clock() - clk1)/(float)(CLOCKS_PER_SEC) );
+ return nNodesEnd;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
diff --git a/src/bdd/reo/reoTransfer.c b/src/bdd/reo/reoTransfer.c
new file mode 100644
index 00000000..752cd3d7
--- /dev/null
+++ b/src/bdd/reo/reoTransfer.c
@@ -0,0 +1,199 @@
+/**CFile****************************************************************
+
+ FileName [reoTransfer.c]
+
+ PackageName [REO: A specialized DD reordering engine.]
+
+ Synopsis [Transfering a DD from the CUDD manager into REO"s internal data structures and back.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - October 15, 2002.]
+
+ Revision [$Id: reoTransfer.c,v 1.0 2002/15/10 03:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "reo.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Transfers the DD into the internal reordering data structure.]
+
+ Description [It is important that the hash table is lossless.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+reo_unit * reoTransferNodesToUnits_rec( reo_man * p, DdNode * F )
+{
+ DdManager * dd = p->dd;
+ reo_unit * pUnit;
+ int HKey, fComp;
+
+ fComp = Cudd_IsComplement(F);
+ F = Cudd_Regular(F);
+
+ // check the hash-table
+ if ( F->ref != 1 )
+ {
+ // search cache - use linear probing
+ for ( HKey = hashKey2(p->Signature,F,p->nTableSize); p->HTable[HKey].Sign == p->Signature; HKey = (HKey+1) % p->nTableSize )
+ if ( p->HTable[HKey].Arg1 == (unsigned)F )
+ {
+ pUnit = (reo_unit*) p->HTable[HKey].Arg2;
+ assert( pUnit );
+ // increment the edge counter
+ pUnit->n++;
+ return Unit_NotCond( pUnit, fComp );
+ }
+ }
+ // the entry in not found in the cache
+
+ // create a new entry
+ pUnit = reoUnitsGetNextUnit( p );
+ pUnit->n = 1;
+ if ( cuddIsConstant(F) )
+ {
+ pUnit->lev = REO_CONST_LEVEL;
+ pUnit->pE = (reo_unit*)((int)(cuddV(F)));
+ pUnit->pT = NULL;
+ // check if the diagram that is being reordering has complement edges
+ if ( F != dd->one )
+ p->fThisIsAdd = 1;
+ // insert the unit into the corresponding plane
+ reoUnitsAddUnitToPlane( &(p->pPlanes[p->nSupp]), pUnit ); // increments the unit counter
+ }
+ else
+ {
+ pUnit->lev = p->pMapToPlanes[F->index];
+ pUnit->pE = reoTransferNodesToUnits_rec( p, cuddE(F) );
+ pUnit->pT = reoTransferNodesToUnits_rec( p, cuddT(F) );
+ // insert the unit into the corresponding plane
+ reoUnitsAddUnitToPlane( &(p->pPlanes[pUnit->lev]), pUnit ); // increments the unit counter
+ }
+
+ // add to the hash table
+ if ( F->ref != 1 )
+ {
+ // the next free entry is already found - it is pointed to by HKey
+ // while we traversed the diagram, the hash entry to which HKey points,
+ // might have been used. Make sure that its signature is different.
+ for ( ; p->HTable[HKey].Sign == p->Signature; HKey = (HKey+1) % p->nTableSize );
+ p->HTable[HKey].Sign = p->Signature;
+ p->HTable[HKey].Arg1 = (unsigned)F;
+ p->HTable[HKey].Arg2 = (unsigned)pUnit;
+ }
+
+ // increment the counter of nodes
+ p->nNodesCur++;
+ return Unit_NotCond( pUnit, fComp );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates the DD from the internal reordering data structure.]
+
+ Description [It is important that the hash table is lossless.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdNode * reoTransferUnitsToNodes_rec( reo_man * p, reo_unit * pUnit )
+{
+ DdManager * dd = p->dd;
+ DdNode * bRes, * E, * T;
+ int HKey, fComp;
+
+ fComp = Cudd_IsComplement(pUnit);
+ pUnit = Unit_Regular(pUnit);
+
+ // check the hash-table
+ if ( pUnit->n != 1 )
+ {
+ for ( HKey = hashKey2(p->Signature,pUnit,p->nTableSize); p->HTable[HKey].Sign == p->Signature; HKey = (HKey+1) % p->nTableSize )
+ if ( p->HTable[HKey].Arg1 == (unsigned)pUnit )
+ {
+ bRes = (DdNode*) p->HTable[HKey].Arg2;
+ assert( bRes );
+ return Cudd_NotCond( bRes, fComp );
+ }
+ }
+
+ // treat the case of constants
+ if ( Unit_IsConstant(pUnit) )
+ {
+ bRes = cuddUniqueConst( dd, ((double)((int)(pUnit->pE))) );
+ cuddRef( bRes );
+ }
+ else
+ {
+ // split and recur on children of this node
+ E = reoTransferUnitsToNodes_rec( p, pUnit->pE );
+ if ( E == NULL )
+ return NULL;
+ cuddRef(E);
+
+ T = reoTransferUnitsToNodes_rec( p, pUnit->pT );
+ if ( T == NULL )
+ {
+ Cudd_RecursiveDeref(dd, E);
+ return NULL;
+ }
+ cuddRef(T);
+
+ // consider the case when Res0 and Res1 are the same node
+ assert( E != T );
+ assert( !Cudd_IsComplement(T) );
+
+ bRes = cuddUniqueInter( dd, p->pMapToDdVarsFinal[pUnit->lev], T, E );
+ if ( bRes == NULL )
+ {
+ Cudd_RecursiveDeref(dd,E);
+ Cudd_RecursiveDeref(dd,T);
+ return NULL;
+ }
+ cuddRef( bRes );
+ cuddDeref( E );
+ cuddDeref( T );
+ }
+
+ // do not keep the result if the ref count is only 1, since it will not be visited again
+ if ( pUnit->n != 1 )
+ {
+ // while we traversed the diagram, the hash entry to which HKey points,
+ // might have been used. Make sure that its signature is different.
+ for ( ; p->HTable[HKey].Sign == p->Signature; HKey = (HKey+1) % p->nTableSize );
+ p->HTable[HKey].Sign = p->Signature;
+ p->HTable[HKey].Arg1 = (unsigned)pUnit;
+ p->HTable[HKey].Arg2 = (unsigned)bRes;
+
+ // add the DD to the referenced DD list in order to be able to store it in cache
+ p->pRefNodes[p->nRefNodes++] = bRes; Cudd_Ref( bRes );
+ // no need to do this, because the garbage collection will not take bRes away
+ // it is held by the diagram in the making
+ }
+ // increment the counter of nodes
+ p->nNodesCur++;
+ cuddDeref( bRes );
+ return Cudd_NotCond( bRes, fComp );
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
diff --git a/src/bdd/reo/reoUnits.c b/src/bdd/reo/reoUnits.c
new file mode 100644
index 00000000..aa86516e
--- /dev/null
+++ b/src/bdd/reo/reoUnits.c
@@ -0,0 +1,184 @@
+/**CFile****************************************************************
+
+ FileName [reoUnits.c]
+
+ PackageName [REO: A specialized DD reordering engine.]
+
+ Synopsis [Procedures which support internal data structures.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - October 15, 2002.]
+
+ Revision [$Id: reoUnits.c,v 1.0 2002/15/10 03:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "reo.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static void reoUnitsAddToFreeUnitList( reo_man * p );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Extract the next unit from the free unit list.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+reo_unit * reoUnitsGetNextUnit(reo_man * p )
+{
+ reo_unit * pUnit;
+ // check there are stil units to extract
+ if ( p->pUnitFreeList == NULL )
+ reoUnitsAddToFreeUnitList( p );
+ // extract the next unit from the linked list
+ pUnit = p->pUnitFreeList;
+ p->pUnitFreeList = pUnit->Next;
+ p->nUnitsUsed++;
+ return pUnit;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the unit to the free unit list.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void reoUnitsRecycleUnit( reo_man * p, reo_unit * pUnit )
+{
+ pUnit->Next = p->pUnitFreeList;
+ p->pUnitFreeList = pUnit;
+ p->nUnitsUsed--;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the list of units to the free unit list.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void reoUnitsRecycleUnitList( reo_man * p, reo_plane * pPlane )
+{
+ reo_unit * pUnit;
+ reo_unit * pTail;
+
+ if ( pPlane->pHead == NULL )
+ return;
+
+ // find the tail
+ for ( pUnit = pPlane->pHead; pUnit; pUnit = pUnit->Next )
+ pTail = pUnit;
+ pTail->Next = p->pUnitFreeList;
+ p->pUnitFreeList = pPlane->pHead;
+ memset( pPlane, 0, sizeof(reo_plane) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Stops the unit dispenser.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void reoUnitsStopDispenser( reo_man * p )
+{
+ int i;
+ for ( i = 0; i < p->nMemChunks; i++ )
+ free( p->pMemChunks[i] );
+// printf("\nThe number of chunks used is %d, each of them %d units\n", p->nMemChunks, REO_CHUNK_SIZE );
+ p->nMemChunks = 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Adds one unit to the list of units which constitutes the plane.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void reoUnitsAddUnitToPlane( reo_plane * pPlane, reo_unit * pUnit )
+{
+ if ( pPlane->pHead == NULL )
+ {
+ pPlane->pHead = pUnit;
+ pUnit->Next = NULL;
+ }
+ else
+ {
+ pUnit->Next = pPlane->pHead;
+ pPlane->pHead = pUnit;
+ }
+ pPlane->statsNodes++;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void reoUnitsAddToFreeUnitList( reo_man * p )
+{
+ int c;
+ // check that we still have chunks left
+ if ( p->nMemChunks == p->nMemChunksAlloc )
+ {
+ printf( "reoUnitsAddToFreeUnitList(): Memory manager ran out of memory!\n" );
+ fflush( stdout );
+ return;
+ }
+ // allocate the next chunk
+ assert( p->pUnitFreeList == NULL );
+ p->pUnitFreeList = ALLOC( reo_unit, REO_CHUNK_SIZE );
+ // split chunks into list-connected units
+ for ( c = 0; c < REO_CHUNK_SIZE-1; c++ )
+ (p->pUnitFreeList + c)->Next = p->pUnitFreeList + c + 1;
+ // set the last pointer to NULL
+ (p->pUnitFreeList + REO_CHUNK_SIZE-1)->Next = NULL;
+ // add the chunk to the array of chunks
+ p->pMemChunks[p->nMemChunks++] = p->pUnitFreeList;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+