node
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
node
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
node
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.
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) : CUDD_TRUE;\ (void) Cudd_NextCube(gen, &cube, &value)) /**Macro*********************************************************************** Synopsis [Iterates over the primes of a Boolean function.] Description [Iterates over the primes of a Boolean function producing a prime and irredundant cover.
CAUTION: It is a mistake to change a diagram on which generation is ongoing.] SideEffects [none] SeeAlso [Cudd_ForeachCube Cudd_FirstPrime Cudd_NextPrime Cudd_GenFree Cudd_IsGenEmpty] ******************************************************************************/ #define Cudd_ForeachPrime(manager, l, u, gen, cube)\ for((gen) = Cudd_FirstPrime(manager, l, u, &cube);\ Cudd_IsGenEmpty(gen) ? Cudd_GenFree(gen) : CUDD_TRUE;\ (void) Cudd_NextPrime(gen, &cube)) /**Macro*********************************************************************** Synopsis [Iterates over the nodes of a decision diagram.] Description [Iterates over the nodes of a decision diagram f.
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) : CUDD_TRUE;\ (void) Cudd_NextNode(gen, &node)) /**Macro*********************************************************************** Synopsis [Iterates over the paths of a ZDD.] Description [Iterates over the paths of a ZDD f.
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) : CUDD_TRUE;\ (void) Cudd_zddNextPath(gen, &path)) /**AutomaticStart*************************************************************/ /*---------------------------------------------------------------------------*/ /* Function prototypes */ /*---------------------------------------------------------------------------*/ #ifndef PBORI_FORCE_ORIGINAL_CUDD extern DdNode * Cudd_addNewVar (PBORI_PREFIX(DdManager) *dd); extern DdNode * Cudd_addNewVarAtLevel (PBORI_PREFIX(DdManager) *dd, int level); extern DdNode * Cudd_bddNewVar (PBORI_PREFIX(DdManager) *dd); extern DdNode * Cudd_bddNewVarAtLevel (PBORI_PREFIX(DdManager) *dd, int level); extern DdNode * Cudd_addIthVar (PBORI_PREFIX(DdManager) *dd, int i); extern DdNode * Cudd_bddIthVar (PBORI_PREFIX(DdManager) *dd, int i); extern DdNode * PBORI_PREFIX(Cudd_zddIthVar) (PBORI_PREFIX(DdManager) *dd, int i); extern int Cudd_zddVarsFromBddVars (PBORI_PREFIX(DdManager) *dd, int multiplicity); extern DdNode * Cudd_addConst (PBORI_PREFIX(DdManager) *dd, CUDD_VALUE_TYPE c); extern int Cudd_IsNonConstant (DdNode *f); extern unsigned long Cudd_ReadStartTime(PBORI_PREFIX(DdManager) *unique); extern unsigned long Cudd_ReadElapsedTime(PBORI_PREFIX(DdManager) *unique); extern void Cudd_SetStartTime(PBORI_PREFIX(DdManager) *unique, unsigned long st); extern void Cudd_ResetStartTime(PBORI_PREFIX(DdManager) *unique); extern unsigned long Cudd_ReadTimeLimit(PBORI_PREFIX(DdManager) *unique); extern void Cudd_SetTimeLimit(PBORI_PREFIX(DdManager) *unique, unsigned long tl); extern void Cudd_UpdateTimeLimit(PBORI_PREFIX(DdManager) * unique); extern void Cudd_IncreaseTimeLimit(PBORI_PREFIX(DdManager) * unique, unsigned long increase); extern void Cudd_UnsetTimeLimit(PBORI_PREFIX(DdManager) *unique); extern int Cudd_TimeLimited(PBORI_PREFIX(DdManager) *unique); extern void Cudd_AutodynEnable (PBORI_PREFIX(DdManager) *unique, Cudd_ReorderingType method); extern void Cudd_AutodynDisable (PBORI_PREFIX(DdManager) *unique); extern int Cudd_ReorderingStatus (PBORI_PREFIX(DdManager) *unique, Cudd_ReorderingType *method); extern void Cudd_AutodynEnableZdd (PBORI_PREFIX(DdManager) *unique, Cudd_ReorderingType method); extern void Cudd_AutodynDisableZdd (PBORI_PREFIX(DdManager) *unique); extern int Cudd_ReorderingStatusZdd (PBORI_PREFIX(DdManager) *unique, Cudd_ReorderingType *method); extern int Cudd_zddRealignmentEnabled (PBORI_PREFIX(DdManager) *unique); extern void Cudd_zddRealignEnable (PBORI_PREFIX(DdManager) *unique); extern void Cudd_zddRealignDisable (PBORI_PREFIX(DdManager) *unique); extern int Cudd_bddRealignmentEnabled (PBORI_PREFIX(DdManager) *unique); extern void Cudd_bddRealignEnable (PBORI_PREFIX(DdManager) *unique); extern void Cudd_bddRealignDisable (PBORI_PREFIX(DdManager) *unique); extern DdNode * Cudd_ReadOne (PBORI_PREFIX(DdManager) *dd); extern DdNode * PBORI_PREFIX(Cudd_ReadZddOne) (PBORI_PREFIX(DdManager) *dd, int i); extern DdNode * PBORI_PREFIX(Cudd_ReadZero) (PBORI_PREFIX(DdManager) *dd); extern DdNode * Cudd_ReadLogicZero (PBORI_PREFIX(DdManager) *dd); extern DdNode * Cudd_ReadPlusInfinity (PBORI_PREFIX(DdManager) *dd); extern DdNode * Cudd_ReadMinusInfinity (PBORI_PREFIX(DdManager) *dd); extern DdNode * Cudd_ReadBackground (PBORI_PREFIX(DdManager) *dd); extern void Cudd_SetBackground (PBORI_PREFIX(DdManager) *dd, DdNode *bck); extern unsigned int Cudd_ReadCacheSlots (PBORI_PREFIX(DdManager) *dd); extern double Cudd_ReadCacheUsedSlots (PBORI_PREFIX(DdManager) * dd); extern double Cudd_ReadCacheLookUps (PBORI_PREFIX(DdManager) *dd); extern double Cudd_ReadCacheHits (PBORI_PREFIX(DdManager) *dd); extern double Cudd_ReadRecursiveCalls (PBORI_PREFIX(DdManager) * dd); extern unsigned int Cudd_ReadMinHit (PBORI_PREFIX(DdManager) *dd); extern void PBORI_PREFIX(Cudd_SetMinHit) (PBORI_PREFIX(DdManager) *dd, unsigned int hr); extern unsigned int Cudd_ReadLooseUpTo (PBORI_PREFIX(DdManager) *dd); extern void Cudd_SetLooseUpTo (PBORI_PREFIX(DdManager) *dd, unsigned int lut); extern unsigned int Cudd_ReadMaxCache (PBORI_PREFIX(DdManager) *dd); extern unsigned int Cudd_ReadMaxCacheHard (PBORI_PREFIX(DdManager) *dd); extern void Cudd_SetMaxCacheHard (PBORI_PREFIX(DdManager) *dd, unsigned int mc); extern int Cudd_ReadSize (PBORI_PREFIX(DdManager) *dd); extern int PBORI_PREFIX(Cudd_ReadZddSize) (PBORI_PREFIX(DdManager) *dd); extern unsigned int Cudd_ReadSlots (PBORI_PREFIX(DdManager) *dd); extern double Cudd_ReadUsedSlots (PBORI_PREFIX(DdManager) * dd); extern double Cudd_ExpectedUsedSlots (PBORI_PREFIX(DdManager) * dd); extern unsigned int Cudd_ReadKeys (PBORI_PREFIX(DdManager) *dd); extern unsigned int Cudd_ReadDead (PBORI_PREFIX(DdManager) *dd); extern unsigned int Cudd_ReadMinDead (PBORI_PREFIX(DdManager) *dd); extern unsigned int Cudd_ReadReorderings (PBORI_PREFIX(DdManager) *dd); extern unsigned int Cudd_ReadMaxReorderings (PBORI_PREFIX(DdManager) *dd); extern void Cudd_SetMaxReorderings (PBORI_PREFIX(DdManager) *dd, unsigned int mr); extern long Cudd_ReadReorderingTime (PBORI_PREFIX(DdManager) * dd); extern int Cudd_ReadGarbageCollections (PBORI_PREFIX(DdManager) * dd); extern long Cudd_ReadGarbageCollectionTime (PBORI_PREFIX(DdManager) * dd); extern double Cudd_ReadNodesFreed (PBORI_PREFIX(DdManager) * dd); extern double Cudd_ReadNodesDropped (PBORI_PREFIX(DdManager) * dd); extern double Cudd_ReadUniqueLookUps (PBORI_PREFIX(DdManager) * dd); extern double Cudd_ReadUniqueLinks (PBORI_PREFIX(DdManager) * dd); extern int Cudd_ReadSiftMaxVar (PBORI_PREFIX(DdManager) *dd); extern void Cudd_SetSiftMaxVar (PBORI_PREFIX(DdManager) *dd, int smv); extern int Cudd_ReadSiftMaxSwap (PBORI_PREFIX(DdManager) *dd); extern void Cudd_SetSiftMaxSwap (PBORI_PREFIX(DdManager) *dd, int sms); extern double Cudd_ReadMaxGrowth (PBORI_PREFIX(DdManager) *dd); extern void Cudd_SetMaxGrowth (PBORI_PREFIX(DdManager) *dd, double mg); extern double Cudd_ReadMaxGrowthAlternate (PBORI_PREFIX(DdManager) * dd); extern void Cudd_SetMaxGrowthAlternate (PBORI_PREFIX(DdManager) * dd, double mg); extern int Cudd_ReadReorderingCycle (PBORI_PREFIX(DdManager) * dd); extern void Cudd_SetReorderingCycle (PBORI_PREFIX(DdManager) * dd, int cycle); #ifdef PBORI_FORCE_ORIGINAL_CUDD extern MtrNode * Cudd_ReadTree (PBORI_PREFIX(DdManager) *dd); extern void Cudd_SetTree (PBORI_PREFIX(DdManager) *dd, MtrNode *tree); extern void Cudd_FreeTree (PBORI_PREFIX(DdManager) *dd); extern MtrNode * Cudd_ReadZddTree (PBORI_PREFIX(DdManager) *dd); extern void Cudd_SetZddTree (PBORI_PREFIX(DdManager) *dd, MtrNode *tree); extern void Cudd_FreeZddTree (PBORI_PREFIX(DdManager) *dd); #endif extern unsigned int PBORI_PREFIX(Cudd_NodeReadIndex) (DdNode *node); extern int Cudd_ReadPerm (PBORI_PREFIX(DdManager) *dd, int i); extern int Cudd_ReadPermZdd (PBORI_PREFIX(DdManager) *dd, int i); extern int Cudd_ReadInvPerm (PBORI_PREFIX(DdManager) *dd, int i); extern int Cudd_ReadInvPermZdd (PBORI_PREFIX(DdManager) *dd, int i); extern DdNode * Cudd_ReadVars (PBORI_PREFIX(DdManager) *dd, int i); extern CUDD_VALUE_TYPE Cudd_ReadEpsilon (PBORI_PREFIX(DdManager) *dd); extern void Cudd_SetEpsilon (PBORI_PREFIX(DdManager) *dd, CUDD_VALUE_TYPE ep); extern Cudd_AggregationType Cudd_ReadGroupcheck (PBORI_PREFIX(DdManager) *dd); extern void Cudd_SetGroupcheck (PBORI_PREFIX(DdManager) *dd, Cudd_AggregationType gc); extern int Cudd_GarbageCollectionEnabled (PBORI_PREFIX(DdManager) *dd); extern void Cudd_EnableGarbageCollection (PBORI_PREFIX(DdManager) *dd); extern void Cudd_DisableGarbageCollection (PBORI_PREFIX(DdManager) *dd); extern int Cudd_DeadAreCounted (PBORI_PREFIX(DdManager) *dd); extern void Cudd_TurnOnCountDead (PBORI_PREFIX(DdManager) *dd); extern void Cudd_TurnOffCountDead (PBORI_PREFIX(DdManager) *dd); extern int Cudd_ReadRecomb (PBORI_PREFIX(DdManager) *dd); extern void Cudd_SetRecomb (PBORI_PREFIX(DdManager) *dd, int recomb); extern int Cudd_ReadSymmviolation (PBORI_PREFIX(DdManager) *dd); extern void Cudd_SetSymmviolation (PBORI_PREFIX(DdManager) *dd, int symmviolation); extern int Cudd_ReadArcviolation (PBORI_PREFIX(DdManager) *dd); extern void Cudd_SetArcviolation (PBORI_PREFIX(DdManager) *dd, int arcviolation); extern int Cudd_ReadPopulationSize (PBORI_PREFIX(DdManager) *dd); extern void Cudd_SetPopulationSize (PBORI_PREFIX(DdManager) *dd, int populationSize); extern int Cudd_ReadNumberXovers (PBORI_PREFIX(DdManager) *dd); extern void Cudd_SetNumberXovers (PBORI_PREFIX(DdManager) *dd, int numberXovers); extern unsigned int Cudd_ReadOrderRandomization(PBORI_PREFIX(DdManager) * dd); extern void Cudd_SetOrderRandomization(PBORI_PREFIX(DdManager) * dd, unsigned int factor); extern unsigned long Cudd_ReadMemoryInUse (PBORI_PREFIX(DdManager) *dd); extern int PBORI_PREFIX(Cudd_PrintInfo) (PBORI_PREFIX(DdManager) *dd, FILE *fp); extern long PBORI_PREFIX(Cudd_ReadPeakNodeCount) (PBORI_PREFIX(DdManager) *dd); extern int PBORI_PREFIX(Cudd_ReadPeakLiveNodeCount) (PBORI_PREFIX(DdManager) * dd); extern long Cudd_ReadNodeCount (PBORI_PREFIX(DdManager) *dd); extern long PBORI_PREFIX(Cudd_zddReadNodeCount) (PBORI_PREFIX(DdManager) *dd); extern int PBORI_PREFIX(Cudd_AddHook) (PBORI_PREFIX(DdManager) *dd, DD_HFP f, Cudd_HookType where); extern int PBORI_PREFIX(Cudd_RemoveHook) (PBORI_PREFIX(DdManager) *dd, DD_HFP f, Cudd_HookType where); extern int Cudd_IsInHook (PBORI_PREFIX(DdManager) * dd, DD_HFP f, Cudd_HookType where); extern int Cudd_StdPreReordHook (PBORI_PREFIX(DdManager) *dd, const char *str, void *data); extern int Cudd_StdPostReordHook (PBORI_PREFIX(DdManager) *dd, const char *str, void *data); extern int Cudd_EnableReorderingReporting (PBORI_PREFIX(DdManager) *dd); extern int Cudd_DisableReorderingReporting (PBORI_PREFIX(DdManager) *dd); extern int Cudd_ReorderingReporting (PBORI_PREFIX(DdManager) *dd); extern int Cudd_PrintGroupedOrder(PBORI_PREFIX(DdManager) * dd, const char *str, void *data); extern int Cudd_EnableOrderingMonitoring(PBORI_PREFIX(DdManager) *dd); extern int Cudd_DisableOrderingMonitoring(PBORI_PREFIX(DdManager) *dd); extern int Cudd_OrderingMonitoring(PBORI_PREFIX(DdManager) *dd); extern Cudd_ErrorType PBORI_PREFIX(Cudd_ReadErrorCode) (PBORI_PREFIX(DdManager) *dd); extern void Cudd_ClearErrorCode (PBORI_PREFIX(DdManager) *dd); extern FILE * Cudd_ReadStdout (PBORI_PREFIX(DdManager) *dd); extern void Cudd_SetStdout (PBORI_PREFIX(DdManager) *dd, FILE *fp); extern FILE * Cudd_ReadStderr (PBORI_PREFIX(DdManager) *dd); extern void Cudd_SetStderr (PBORI_PREFIX(DdManager) *dd, FILE *fp); extern unsigned int PBORI_PREFIX(Cudd_ReadNextReordering) (PBORI_PREFIX(DdManager) *dd); extern void Cudd_SetNextReordering (PBORI_PREFIX(DdManager) *dd, unsigned int next); extern double Cudd_ReadSwapSteps (PBORI_PREFIX(DdManager) *dd); extern unsigned int Cudd_ReadMaxLive (PBORI_PREFIX(DdManager) *dd); extern void Cudd_SetMaxLive (PBORI_PREFIX(DdManager) *dd, unsigned int maxLive); extern unsigned long Cudd_ReadMaxMemory (PBORI_PREFIX(DdManager) *dd); extern void Cudd_SetMaxMemory (PBORI_PREFIX(DdManager) *dd, unsigned long maxMemory); extern int Cudd_bddBindVar (PBORI_PREFIX(DdManager) *dd, int index); extern int Cudd_bddUnbindVar (PBORI_PREFIX(DdManager) *dd, int index); extern int Cudd_bddVarIsBound (PBORI_PREFIX(DdManager) *dd, int index); extern DdNode * Cudd_addExistAbstract (PBORI_PREFIX(DdManager) *manager, DdNode *f, DdNode *cube); extern DdNode * Cudd_addUnivAbstract (PBORI_PREFIX(DdManager) *manager, DdNode *f, DdNode *cube); extern DdNode * Cudd_addOrAbstract (PBORI_PREFIX(DdManager) *manager, DdNode *f, DdNode *cube); extern DdNode * Cudd_addApply (PBORI_PREFIX(DdManager) *dd, DdNode * (*)(PBORI_PREFIX(DdManager) *, DdNode **, DdNode **), DdNode *f, DdNode *g); extern DdNode * Cudd_addPlus (PBORI_PREFIX(DdManager) *dd, DdNode **f, DdNode **g); extern DdNode * Cudd_addTimes (PBORI_PREFIX(DdManager) *dd, DdNode **f, DdNode **g); extern DdNode * Cudd_addThreshold (PBORI_PREFIX(DdManager) *dd, DdNode **f, DdNode **g); extern DdNode * Cudd_addSetNZ (PBORI_PREFIX(DdManager) *dd, DdNode **f, DdNode **g); extern DdNode * Cudd_addDivide (PBORI_PREFIX(DdManager) *dd, DdNode **f, DdNode **g); extern DdNode * Cudd_addMinus (PBORI_PREFIX(DdManager) *dd, DdNode **f, DdNode **g); extern DdNode * Cudd_addMinimum (PBORI_PREFIX(DdManager) *dd, DdNode **f, DdNode **g); extern DdNode * Cudd_addMaximum (PBORI_PREFIX(DdManager) *dd, DdNode **f, DdNode **g); extern DdNode * Cudd_addOneZeroMaximum (PBORI_PREFIX(DdManager) *dd, DdNode **f, DdNode **g); extern DdNode * Cudd_addDiff (PBORI_PREFIX(DdManager) *dd, DdNode **f, DdNode **g); extern DdNode * Cudd_addAgreement (PBORI_PREFIX(DdManager) *dd, DdNode **f, DdNode **g); extern DdNode * Cudd_addOr (PBORI_PREFIX(DdManager) *dd, DdNode **f, DdNode **g); extern DdNode * Cudd_addNand (PBORI_PREFIX(DdManager) *dd, DdNode **f, DdNode **g); extern DdNode * Cudd_addNor (PBORI_PREFIX(DdManager) *dd, DdNode **f, DdNode **g); extern DdNode * Cudd_addXor (PBORI_PREFIX(DdManager) *dd, DdNode **f, DdNode **g); extern DdNode * Cudd_addXnor (PBORI_PREFIX(DdManager) *dd, DdNode **f, DdNode **g); extern DdNode * Cudd_addMonadicApply (PBORI_PREFIX(DdManager) * dd, DdNode * (*op)(PBORI_PREFIX(DdManager) *, DdNode *), DdNode * f); extern DdNode * Cudd_addLog (PBORI_PREFIX(DdManager) * dd, DdNode * f); extern DdNode * Cudd_addFindMax (PBORI_PREFIX(DdManager) *dd, DdNode *f); extern DdNode * Cudd_addFindMin (PBORI_PREFIX(DdManager) *dd, DdNode *f); extern DdNode * Cudd_addIthBit (PBORI_PREFIX(DdManager) *dd, DdNode *f, int bit); extern DdNode * Cudd_addScalarInverse (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *epsilon); extern DdNode * Cudd_addIte (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g, DdNode *h); extern DdNode * Cudd_addIteConstant (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g, DdNode *h); extern DdNode * Cudd_addEvalConst (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g); extern int Cudd_addLeq (PBORI_PREFIX(DdManager) * dd, DdNode * f, DdNode * g); extern DdNode * Cudd_addCmpl (PBORI_PREFIX(DdManager) *dd, DdNode *f); extern DdNode * Cudd_addNegate (PBORI_PREFIX(DdManager) *dd, DdNode *f); extern DdNode * Cudd_addRoundOff (PBORI_PREFIX(DdManager) *dd, DdNode *f, int N); extern DdNode * Cudd_addWalsh (PBORI_PREFIX(DdManager) *dd, DdNode **x, DdNode **y, int n); extern DdNode * Cudd_addResidue (PBORI_PREFIX(DdManager) *dd, int n, int m, int options, int top); extern DdNode * Cudd_bddAndAbstract (PBORI_PREFIX(DdManager) *manager, DdNode *f, DdNode *g, DdNode *cube); extern DdNode * Cudd_bddAndAbstractLimit (PBORI_PREFIX(DdManager) *manager, DdNode *f, DdNode *g, DdNode *cube, unsigned int limit); extern int Cudd_ApaNumberOfDigits (int binaryDigits); extern DdApaNumber Cudd_NewApaNumber (int digits); extern void Cudd_ApaCopy (int digits, DdApaNumber source, DdApaNumber dest); extern DdApaDigit Cudd_ApaAdd (int digits, DdApaNumber a, DdApaNumber b, DdApaNumber sum); extern DdApaDigit Cudd_ApaSubtract (int digits, DdApaNumber a, DdApaNumber b, DdApaNumber diff); extern DdApaDigit Cudd_ApaShortDivision (int digits, DdApaNumber dividend, DdApaDigit divisor, DdApaNumber quotient); extern unsigned int Cudd_ApaIntDivision (int digits, DdApaNumber dividend, unsigned int divisor, DdApaNumber quotient); extern void Cudd_ApaShiftRight (int digits, DdApaDigit in, DdApaNumber a, DdApaNumber b); extern void Cudd_ApaSetToLiteral (int digits, DdApaNumber number, DdApaDigit literal); extern void Cudd_ApaPowerOfTwo (int digits, DdApaNumber number, int power); extern int Cudd_ApaCompare (int digitsFirst, DdApaNumber first, int digitsSecond, DdApaNumber second); extern int Cudd_ApaCompareRatios (int digitsFirst, DdApaNumber firstNum, unsigned int firstDen, int digitsSecond, DdApaNumber secondNum, unsigned int secondDen); extern int Cudd_ApaPrintHex (FILE *fp, int digits, DdApaNumber number); extern int Cudd_ApaPrintDecimal (FILE *fp, int digits, DdApaNumber number); extern int Cudd_ApaPrintExponential (FILE * fp, int digits, DdApaNumber number, int precision); extern DdApaNumber Cudd_ApaCountMinterm (PBORI_PREFIX(DdManager) *manager, DdNode *node, int nvars, int *digits); extern int Cudd_ApaPrintMinterm (FILE *fp, PBORI_PREFIX(DdManager) *dd, DdNode *node, int nvars); extern int Cudd_ApaPrintMintermExp (FILE * fp, PBORI_PREFIX(DdManager) * dd, DdNode * node, int nvars, int precision); extern int Cudd_ApaPrintDensity (FILE * fp, PBORI_PREFIX(DdManager) * dd, DdNode * node, int nvars); extern DdNode * Cudd_UnderApprox (PBORI_PREFIX(DdManager) *dd, DdNode *f, int numVars, int threshold, int safe, double quality); extern DdNode * Cudd_OverApprox (PBORI_PREFIX(DdManager) *dd, DdNode *f, int numVars, int threshold, int safe, double quality); extern DdNode * Cudd_RemapUnderApprox (PBORI_PREFIX(DdManager) *dd, DdNode *f, int numVars, int threshold, double quality); extern DdNode * Cudd_RemapOverApprox (PBORI_PREFIX(DdManager) *dd, DdNode *f, int numVars, int threshold, double quality); extern DdNode * Cudd_BiasedUnderApprox (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *b, int numVars, int threshold, double quality1, double quality0); extern DdNode * Cudd_BiasedOverApprox (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *b, int numVars, int threshold, double quality1, double quality0); extern DdNode * Cudd_bddExistAbstract (PBORI_PREFIX(DdManager) *manager, DdNode *f, DdNode *cube); extern DdNode * Cudd_bddExistAbstractLimit(PBORI_PREFIX(DdManager) * manager, DdNode * f, DdNode * cube, unsigned int limit); extern DdNode * Cudd_bddXorExistAbstract (PBORI_PREFIX(DdManager) *manager, DdNode *f, DdNode *g, DdNode *cube); extern DdNode * Cudd_bddUnivAbstract (PBORI_PREFIX(DdManager) *manager, DdNode *f, DdNode *cube); extern DdNode * Cudd_bddBooleanDiff (PBORI_PREFIX(DdManager) *manager, DdNode *f, int x); extern int Cudd_bddVarIsDependent (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *var); extern double Cudd_bddCorrelation (PBORI_PREFIX(DdManager) *manager, DdNode *f, DdNode *g); extern double Cudd_bddCorrelationWeights (PBORI_PREFIX(DdManager) *manager, DdNode *f, DdNode *g, double *prob); extern DdNode * Cudd_bddIte (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g, DdNode *h); extern DdNode * Cudd_bddIteLimit (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g, DdNode *h, unsigned int limit); extern DdNode * Cudd_bddIteConstant (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g, DdNode *h); extern DdNode * Cudd_bddIntersect (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g); extern DdNode * Cudd_bddAnd (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g); extern DdNode * Cudd_bddAndLimit (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g, unsigned int limit); extern DdNode * Cudd_bddOr (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g); extern DdNode * Cudd_bddOrLimit (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g, unsigned int limit); extern DdNode * Cudd_bddNand (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g); extern DdNode * Cudd_bddNor (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g); extern DdNode * Cudd_bddXor (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g); extern DdNode * Cudd_bddXnor (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g); extern DdNode * Cudd_bddXnorLimit (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g, unsigned int limit); extern int Cudd_bddLeq (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g); extern DdNode * Cudd_addBddThreshold (PBORI_PREFIX(DdManager) *dd, DdNode *f, CUDD_VALUE_TYPE value); extern DdNode * Cudd_addBddStrictThreshold (PBORI_PREFIX(DdManager) *dd, DdNode *f, CUDD_VALUE_TYPE value); extern DdNode * Cudd_addBddInterval (PBORI_PREFIX(DdManager) *dd, DdNode *f, CUDD_VALUE_TYPE lower, CUDD_VALUE_TYPE upper); extern DdNode * Cudd_addBddIthBit (PBORI_PREFIX(DdManager) *dd, DdNode *f, int bit); extern DdNode * Cudd_BddToAdd (PBORI_PREFIX(DdManager) *dd, DdNode *B); extern DdNode * Cudd_addBddPattern (PBORI_PREFIX(DdManager) *dd, DdNode *f); extern DdNode * Cudd_bddTransfer (PBORI_PREFIX(DdManager) *ddSource, PBORI_PREFIX(DdManager) *ddDestination, DdNode *f); extern int Cudd_DebugCheck (PBORI_PREFIX(DdManager) *table); extern int Cudd_CheckKeys (PBORI_PREFIX(DdManager) *table); extern DdNode * Cudd_bddClippingAnd (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g, int maxDepth, int direction); extern DdNode * Cudd_bddClippingAndAbstract (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g, DdNode *cube, int maxDepth, int direction); extern DdNode * Cudd_Cofactor (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g); extern int Cudd_CheckCube (PBORI_PREFIX(DdManager) *dd, DdNode *g); extern DdNode * Cudd_bddCompose (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g, int v); extern DdNode * Cudd_addCompose (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g, int v); extern DdNode * Cudd_addPermute (PBORI_PREFIX(DdManager) *manager, DdNode *node, int *permut); extern DdNode * Cudd_addSwapVariables (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode **x, DdNode **y, int n); extern DdNode * Cudd_bddPermute (PBORI_PREFIX(DdManager) *manager, DdNode *node, int *permut); extern DdNode * Cudd_bddVarMap (PBORI_PREFIX(DdManager) *manager, DdNode *f); extern int Cudd_SetVarMap (PBORI_PREFIX(DdManager) *manager, DdNode **x, DdNode **y, int n); extern DdNode * Cudd_bddSwapVariables (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode **x, DdNode **y, int n); extern DdNode * Cudd_bddAdjPermuteX (PBORI_PREFIX(DdManager) *dd, DdNode *B, DdNode **x, int n); extern DdNode * Cudd_addVectorCompose (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode **vector); extern DdNode * Cudd_addGeneralVectorCompose (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode **vectorOn, DdNode **vectorOff); extern DdNode * Cudd_addNonSimCompose (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode **vector); extern DdNode * Cudd_bddVectorCompose (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode **vector); extern int Cudd_bddApproxConjDecomp (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode ***conjuncts); extern int Cudd_bddApproxDisjDecomp (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode ***disjuncts); extern int Cudd_bddIterConjDecomp (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode ***conjuncts); extern int Cudd_bddIterDisjDecomp (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode ***disjuncts); extern int Cudd_bddGenConjDecomp (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode ***conjuncts); extern int Cudd_bddGenDisjDecomp (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode ***disjuncts); extern int Cudd_bddVarConjDecomp (PBORI_PREFIX(DdManager) *dd, DdNode * f, DdNode ***conjuncts); extern int Cudd_bddVarDisjDecomp (PBORI_PREFIX(DdManager) *dd, DdNode * f, DdNode ***disjuncts); extern DdNode * Cudd_FindEssential (PBORI_PREFIX(DdManager) *dd, DdNode *f); extern int Cudd_bddIsVarEssential (PBORI_PREFIX(DdManager) *manager, DdNode *f, int id, int phase); extern DdTlcInfo * Cudd_FindTwoLiteralClauses (PBORI_PREFIX(DdManager) * dd, DdNode * f); extern int Cudd_PrintTwoLiteralClauses (PBORI_PREFIX(DdManager) * dd, DdNode * f, char **names, FILE *fp); extern int Cudd_ReadIthClause (DdTlcInfo * tlc, int i, DdHalfWord *var1, DdHalfWord *var2, int *phase1, int *phase2); extern void Cudd_tlcInfoFree (DdTlcInfo * t); extern int Cudd_DumpBlif (PBORI_PREFIX(DdManager) *dd, int n, DdNode **f, char **inames, char **onames, char *mname, FILE *fp, int mv); extern int Cudd_DumpBlifBody (PBORI_PREFIX(DdManager) *dd, int n, DdNode **f, char **inames, char **onames, FILE *fp, int mv); extern int Cudd_DumpDot (PBORI_PREFIX(DdManager) *dd, int n, DdNode **f, char **inames, char **onames, FILE *fp); extern int Cudd_DumpDaVinci (PBORI_PREFIX(DdManager) *dd, int n, DdNode **f, char **inames, char **onames, FILE *fp); extern int Cudd_DumpDDcal (PBORI_PREFIX(DdManager) *dd, int n, DdNode **f, char **inames, char **onames, FILE *fp); extern int Cudd_DumpFactoredForm (PBORI_PREFIX(DdManager) *dd, int n, DdNode **f, char **inames, char **onames, FILE *fp); extern DdNode * Cudd_bddConstrain (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *c); extern DdNode * Cudd_bddRestrict (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *c); extern DdNode * Cudd_bddNPAnd (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *c); extern DdNode * Cudd_addConstrain (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *c); extern DdNode ** Cudd_bddConstrainDecomp (PBORI_PREFIX(DdManager) *dd, DdNode *f); extern DdNode * Cudd_addRestrict (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *c); extern DdNode ** Cudd_bddCharToVect (PBORI_PREFIX(DdManager) *dd, DdNode *f); extern DdNode * Cudd_bddLICompaction (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *c); extern DdNode * Cudd_bddSqueeze (PBORI_PREFIX(DdManager) *dd, DdNode *l, DdNode *u); extern DdNode * Cudd_bddMinimize (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *c); extern DdNode * Cudd_SubsetCompress (PBORI_PREFIX(DdManager) *dd, DdNode *f, int nvars, int threshold); extern DdNode * Cudd_SupersetCompress (PBORI_PREFIX(DdManager) *dd, DdNode *f, int nvars, int threshold); #ifdef PBORI_FORCE_ORIGINAL_CUDD extern MtrNode * Cudd_MakeTreeNode (PBORI_PREFIX(DdManager) *dd, unsigned int low, unsigned int size, unsigned int type); #endif extern int Cudd_addHarwell (FILE *fp, PBORI_PREFIX(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 PBORI_PREFIX(DdManager) * PBORI_PREFIX(Cudd_Init) (unsigned int numVars, unsigned int numVarsZ, unsigned int numSlots, unsigned int cacheSize, unsigned long maxMemory); extern void PBORI_PREFIX(Cudd_Quit) (PBORI_PREFIX(DdManager) *unique); extern int Cudd_PrintLinear (PBORI_PREFIX(DdManager) *table); extern int Cudd_ReadLinear (PBORI_PREFIX(DdManager) *table, int x, int y); extern DdNode * Cudd_bddLiteralSetIntersection (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g); extern DdNode * Cudd_addMatrixMultiply (PBORI_PREFIX(DdManager) *dd, DdNode *A, DdNode *B, DdNode **z, int nz); extern DdNode * Cudd_addTimesPlus (PBORI_PREFIX(DdManager) *dd, DdNode *A, DdNode *B, DdNode **z, int nz); extern DdNode * Cudd_addTriangle (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g, DdNode **z, int nz); extern DdNode * Cudd_addOuterSum (PBORI_PREFIX(DdManager) *dd, DdNode *M, DdNode *r, DdNode *c); extern DdNode * Cudd_PrioritySelect (PBORI_PREFIX(DdManager) *dd, DdNode *R, DdNode **x, DdNode **y, DdNode **z, DdNode *Pi, int n, DdNode * (*)(PBORI_PREFIX(DdManager) *, int, DdNode **, DdNode **, DdNode **)); extern DdNode * Cudd_Xgty (PBORI_PREFIX(DdManager) *dd, int N, DdNode **z, DdNode **x, DdNode **y); extern DdNode * Cudd_Xeqy (PBORI_PREFIX(DdManager) *dd, int N, DdNode **x, DdNode **y); extern DdNode * Cudd_addXeqy (PBORI_PREFIX(DdManager) *dd, int N, DdNode **x, DdNode **y); extern DdNode * Cudd_Dxygtdxz (PBORI_PREFIX(DdManager) *dd, int N, DdNode **x, DdNode **y, DdNode **z); extern DdNode * Cudd_Dxygtdyz (PBORI_PREFIX(DdManager) *dd, int N, DdNode **x, DdNode **y, DdNode **z); extern DdNode * Cudd_Inequality (PBORI_PREFIX(DdManager) * dd, int N, int c, DdNode ** x, DdNode ** y); extern DdNode * Cudd_Disequality (PBORI_PREFIX(DdManager) * dd, int N, int c, DdNode ** x, DdNode ** y); extern DdNode * Cudd_bddInterval (PBORI_PREFIX(DdManager) * dd, int N, DdNode ** x, unsigned int lowerB, unsigned int upperB); extern DdNode * Cudd_CProjection (PBORI_PREFIX(DdManager) *dd, DdNode *R, DdNode *Y); extern DdNode * Cudd_addHamming (PBORI_PREFIX(DdManager) *dd, DdNode **xVars, DdNode **yVars, int nVars); extern int Cudd_MinHammingDist (PBORI_PREFIX(DdManager) *dd, DdNode *f, int *minterm, int upperBound); extern DdNode * Cudd_bddClosestCube (PBORI_PREFIX(DdManager) *dd, DdNode * f, DdNode *g, int *distance); extern int Cudd_addRead (FILE *fp, PBORI_PREFIX(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 (FILE *fp, PBORI_PREFIX(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 PBORI_PREFIX(Cudd_Ref) (DdNode *n); extern void PBORI_PREFIX(Cudd_RecursiveDeref) (PBORI_PREFIX(DdManager) *table, DdNode *n); extern void Cudd_IterDerefBdd (PBORI_PREFIX(DdManager) *table, DdNode *n); extern void Cudd_DelayedDerefBdd (PBORI_PREFIX(DdManager) * table, DdNode * n); extern void PBORI_PREFIX(Cudd_RecursiveDerefZdd) (PBORI_PREFIX(DdManager) *table, DdNode *n); extern void PBORI_PREFIX(Cudd_Deref (DdNode *node)); extern int PBORI_PREFIX(Cudd_CheckZeroRef) (PBORI_PREFIX(DdManager) *manager); extern int Cudd_ReduceHeap (PBORI_PREFIX(DdManager) *table, Cudd_ReorderingType heuristic, int minsize); extern int Cudd_ShuffleHeap (PBORI_PREFIX(DdManager) *table, int *permutation); extern DdNode * Cudd_Eval (PBORI_PREFIX(DdManager) *dd, DdNode *f, int *inputs); extern DdNode * Cudd_ShortestPath (PBORI_PREFIX(DdManager) *manager, DdNode *f, int *weight, int *support, int *length); extern DdNode * Cudd_LargestCube (PBORI_PREFIX(DdManager) *manager, DdNode *f, int *length); extern int Cudd_ShortestLength (PBORI_PREFIX(DdManager) *manager, DdNode *f, int *weight); extern DdNode * Cudd_Decreasing (PBORI_PREFIX(DdManager) *dd, DdNode *f, int i); extern DdNode * Cudd_Increasing (PBORI_PREFIX(DdManager) *dd, DdNode *f, int i); extern int Cudd_EquivDC (PBORI_PREFIX(DdManager) *dd, DdNode *F, DdNode *G, DdNode *D); extern int Cudd_bddLeqUnless (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g, DdNode *D); extern int Cudd_EqualSupNorm (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g, CUDD_VALUE_TYPE tolerance, int pr); extern DdNode * Cudd_bddMakePrime (PBORI_PREFIX(DdManager) *dd, DdNode *cube, DdNode *f); extern DdNode * Cudd_bddMaximallyExpand(PBORI_PREFIX(DdManager) *dd, DdNode *lb, DdNode *ub, DdNode *f); extern DdNode * Cudd_bddLargestPrimeUnate(PBORI_PREFIX(DdManager) *dd , DdNode *f, DdNode *phaseBdd); extern double * Cudd_CofMinterm (PBORI_PREFIX(DdManager) *dd, DdNode *node); extern DdNode * Cudd_SolveEqn (PBORI_PREFIX(DdManager) * bdd, DdNode *F, DdNode *Y, DdNode **G, int **yIndex, int n); extern DdNode * Cudd_VerifySol (PBORI_PREFIX(DdManager) * bdd, DdNode *F, DdNode **G, int *yIndex, int n); extern DdNode * Cudd_SplitSet (PBORI_PREFIX(DdManager) *manager, DdNode *S, DdNode **xVars, int n, double m); extern DdNode * Cudd_SubsetHeavyBranch (PBORI_PREFIX(DdManager) *dd, DdNode *f, int numVars, int threshold); extern DdNode * Cudd_SupersetHeavyBranch (PBORI_PREFIX(DdManager) *dd, DdNode *f, int numVars, int threshold); extern DdNode * Cudd_SubsetShortPaths (PBORI_PREFIX(DdManager) *dd, DdNode *f, int numVars, int threshold, int hardlimit); extern DdNode * Cudd_SupersetShortPaths (PBORI_PREFIX(DdManager) *dd, DdNode *f, int numVars, int threshold, int hardlimit); extern void Cudd_SymmProfile (PBORI_PREFIX(DdManager) *table, int lower, int upper); extern unsigned int Cudd_Prime (unsigned int p); extern int Cudd_Reserve(PBORI_PREFIX(DdManager) *manager, int amount); extern int Cudd_PrintMinterm (PBORI_PREFIX(DdManager) *manager, DdNode *node); extern int Cudd_bddPrintCover (PBORI_PREFIX(DdManager) *dd, DdNode *l, DdNode *u); extern int Cudd_PrintDebug (PBORI_PREFIX(DdManager) *dd, DdNode *f, int n, int pr); extern int Cudd_DagSize (DdNode *node); extern int Cudd_EstimateCofactor (PBORI_PREFIX(DdManager) *dd, DdNode * node, int i, int phase); extern int Cudd_EstimateCofactorSimple (DdNode * node, int i); extern int Cudd_SharingSize (DdNode **nodeArray, int n); #ifdef PBORI_FORCE_ORIGINAL_CUDD extern double Cudd_CountMinterm (PBORI_PREFIX(DdManager) *manager, DdNode *node, int nvars); extern int Cudd_EpdCountMinterm (PBORI_PREFIX(DdManager) *manager, DdNode *node, int nvars, EpDouble *epd); #endif extern double Cudd_CountPath (DdNode *node); extern double Cudd_CountPathsToNonZero (DdNode *node); extern int Cudd_SupportIndices(PBORI_PREFIX(DdManager) * dd, DdNode * f, int **indices); extern DdNode * Cudd_Support (PBORI_PREFIX(DdManager) *dd, DdNode *f); extern int * Cudd_SupportIndex (PBORI_PREFIX(DdManager) *dd, DdNode *f); extern int PBORI_PREFIX(Cudd_SupportSize) (PBORI_PREFIX(DdManager) *dd, DdNode *f); extern int Cudd_VectorSupportIndices(PBORI_PREFIX(DdManager) * dd, DdNode ** F, int n, int **indices); extern DdNode * Cudd_VectorSupport (PBORI_PREFIX(DdManager) *dd, DdNode **F, int n); extern int * Cudd_VectorSupportIndex (PBORI_PREFIX(DdManager) *dd, DdNode **F, int n); extern int Cudd_VectorSupportSize (PBORI_PREFIX(DdManager) *dd, DdNode **F, int n); extern int Cudd_ClassifySupport (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g, DdNode **common, DdNode **onlyF, DdNode **onlyG); extern int Cudd_CountLeaves (DdNode *node); extern int Cudd_bddPickOneCube (PBORI_PREFIX(DdManager) *ddm, DdNode *node, char *string); extern DdNode * Cudd_bddPickOneMinterm (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode **vars, int n); extern DdNode ** Cudd_bddPickArbitraryMinterms (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode **vars, int n, int k); extern DdNode * Cudd_SubsetWithMaskVars (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode **vars, int nvars, DdNode **maskVars, int mvars); extern DdGen * Cudd_FirstCube (PBORI_PREFIX(DdManager) *dd, DdNode *f, int **cube, CUDD_VALUE_TYPE *value); extern int Cudd_NextCube (DdGen *gen, int **cube, CUDD_VALUE_TYPE *value); extern DdGen * Cudd_FirstPrime(PBORI_PREFIX(DdManager) *dd, DdNode *l, DdNode *u, int **cube); extern int Cudd_NextPrime(DdGen *gen, int **cube); extern DdNode * Cudd_bddComputeCube (PBORI_PREFIX(DdManager) *dd, DdNode **vars, int *phase, int n); extern DdNode * Cudd_addComputeCube (PBORI_PREFIX(DdManager) *dd, DdNode **vars, int *phase, int n); extern DdNode * Cudd_CubeArrayToBdd (PBORI_PREFIX(DdManager) *dd, int *array); extern int Cudd_BddToCubeArray (PBORI_PREFIX(DdManager) *dd, DdNode *cube, int *array); extern DdGen * Cudd_FirstNode (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode **node); extern int Cudd_NextNode (DdGen *gen, DdNode **node); extern int Cudd_GenFree (DdGen *gen); extern int Cudd_IsGenEmpty (DdGen *gen); extern DdNode * Cudd_IndicesToCube (PBORI_PREFIX(DdManager) *dd, int *array, int n); extern void Cudd_PrintVersion (FILE *fp); extern double Cudd_AverageDistance (PBORI_PREFIX(DdManager) *dd); extern long Cudd_Random (void); extern void Cudd_Srandom (long seed); extern double Cudd_Density (PBORI_PREFIX(DdManager) *dd, DdNode *f, int nvars); #endif /* PBORI_FORCE_ORIGINAL_CUDD*/ extern void PBORI_PREFIX(Cudd_OutOfMem) (long size); extern int PBORI_PREFIX(Cudd_zddCount) (PBORI_PREFIX(DdManager) *zdd, DdNode *P); extern double PBORI_PREFIX(Cudd_zddCountDouble) (PBORI_PREFIX(DdManager) *zdd, DdNode *P); extern DdNode * PBORI_PREFIX(Cudd_zddProduct) (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g); extern DdNode * PBORI_PREFIX(Cudd_zddUnateProduct) (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g); extern DdNode * PBORI_PREFIX(Cudd_zddWeakDiv) (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g); extern DdNode * PBORI_PREFIX(Cudd_zddDivide) (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g); extern DdNode * PBORI_PREFIX(Cudd_zddWeakDivF) (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g); extern DdNode * PBORI_PREFIX(Cudd_zddDivideF) (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g); extern DdNode * PBORI_PREFIX(Cudd_zddComplement) (PBORI_PREFIX(DdManager) *dd, DdNode *node); #ifdef PBORI_FORCE_ORIGINAL_CUDD extern MtrNode * Cudd_MakeZddTreeNode (PBORI_PREFIX(DdManager) *dd, unsigned int low, unsigned int size, unsigned int type); #endif extern DdNode * PBORI_PREFIX(Cudd_zddIsop) (PBORI_PREFIX(DdManager) *dd, DdNode *L, DdNode *U, DdNode **zdd_I); extern DdNode * PBORI_PREFIX(Cudd_bddIsop) (PBORI_PREFIX(DdManager) *dd, DdNode *L, DdNode *U); extern DdNode * PBORI_PREFIX(Cudd_MakeBddFromZddCover) (PBORI_PREFIX(DdManager) *dd, DdNode *node); extern int PBORI_PREFIX(Cudd_zddDagSize) (DdNode *p_node); extern double PBORI_PREFIX(Cudd_zddCountMinterm) (PBORI_PREFIX(DdManager) *zdd, DdNode *node, int path); extern void PBORI_PREFIX(Cudd_zddPrintSubtable) (PBORI_PREFIX(DdManager) *table); extern DdNode * PBORI_PREFIX(Cudd_zddPortFromBdd) (PBORI_PREFIX(DdManager) *dd, DdNode *B); extern DdNode * PBORI_PREFIX(Cudd_zddPortToBdd) (PBORI_PREFIX(DdManager) *dd, DdNode *f); extern int PBORI_PREFIX(Cudd_zddReduceHeap) (PBORI_PREFIX(DdManager) *table, Cudd_ReorderingType heuristic, int minsize); extern int PBORI_PREFIX(Cudd_zddShuffleHeap) (PBORI_PREFIX(DdManager) *table, int *permutation); extern DdNode * PBORI_PREFIX(Cudd_zddIte) (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g, DdNode *h); extern DdNode * PBORI_PREFIX(Cudd_zddUnion) (PBORI_PREFIX(DdManager) *dd, DdNode *P, DdNode *Q); extern DdNode * PBORI_PREFIX(Cudd_zddIntersect) (PBORI_PREFIX(DdManager) *dd, DdNode *P, DdNode *Q); extern DdNode * PBORI_PREFIX(Cudd_zddDiff) (PBORI_PREFIX(DdManager) *dd, DdNode *P, DdNode *Q); extern DdNode * PBORI_PREFIX(Cudd_zddDiffConst) (PBORI_PREFIX(DdManager) *zdd, DdNode *P, DdNode *Q); extern DdNode * PBORI_PREFIX(Cudd_zddSubset1) (PBORI_PREFIX(DdManager) *dd, DdNode *P, int var); extern DdNode * PBORI_PREFIX(Cudd_zddSubset0) (PBORI_PREFIX(DdManager) *dd, DdNode *P, int var); extern DdNode * PBORI_PREFIX(Cudd_zddChange) (PBORI_PREFIX(DdManager) *dd, DdNode *P, int var); extern void PBORI_PREFIX(Cudd_zddSymmProfile) (PBORI_PREFIX(DdManager) *table, int lower, int upper); extern int PBORI_PREFIX(Cudd_zddPrintMinterm) (PBORI_PREFIX(DdManager) *zdd, DdNode *node); extern int PBORI_PREFIX(Cudd_zddPrintCover) (PBORI_PREFIX(DdManager) *zdd, DdNode *node); extern int PBORI_PREFIX(Cudd_zddPrintDebug) (PBORI_PREFIX(DdManager) *zdd, DdNode *f, int n, int pr); extern DdGen * PBORI_PREFIX(Cudd_zddFirstPath) (PBORI_PREFIX(DdManager) *zdd, DdNode *f, int **path); extern int PBORI_PREFIX(Cudd_zddNextPath) (DdGen *gen, int **path); extern char * PBORI_PREFIX(Cudd_zddCoverPathToString) (PBORI_PREFIX(DdManager) *zdd, int *path, char *str); extern DdNode * PBORI_PREFIX(Cudd_zddSupport) (PBORI_PREFIX(DdManager) * dd, DdNode * f); extern int PBORI_PREFIX(Cudd_zddDumpDot) (PBORI_PREFIX(DdManager) *dd, int n, DdNode **f, char **inames, char **onames, FILE *fp); #ifndef PBORI_FORCE_ORIGINAL_CUDD extern int Cudd_bddSetPiVar (PBORI_PREFIX(DdManager) *dd, int index); extern int Cudd_bddSetPsVar (PBORI_PREFIX(DdManager) *dd, int index); extern int Cudd_bddSetNsVar (PBORI_PREFIX(DdManager) *dd, int index); extern int Cudd_bddIsPiVar (PBORI_PREFIX(DdManager) *dd, int index); extern int Cudd_bddIsPsVar (PBORI_PREFIX(DdManager) *dd, int index); extern int Cudd_bddIsNsVar (PBORI_PREFIX(DdManager) *dd, int index); extern int Cudd_bddSetPairIndex (PBORI_PREFIX(DdManager) *dd, int index, int pairIndex); extern int Cudd_bddReadPairIndex (PBORI_PREFIX(DdManager) *dd, int index); extern int Cudd_bddSetVarToBeGrouped (PBORI_PREFIX(DdManager) *dd, int index); extern int Cudd_bddSetVarHardGroup (PBORI_PREFIX(DdManager) *dd, int index); extern int Cudd_bddResetVarToBeGrouped (PBORI_PREFIX(DdManager) *dd, int index); extern int Cudd_bddIsVarToBeGrouped (PBORI_PREFIX(DdManager) *dd, int index); extern int Cudd_bddSetVarToBeUngrouped (PBORI_PREFIX(DdManager) *dd, int index); extern int Cudd_bddIsVarToBeUngrouped (PBORI_PREFIX(DdManager) *dd, int index); extern int Cudd_bddIsVarHardGroup (PBORI_PREFIX(DdManager) *dd, int index); #endif /**AutomaticEnd***************************************************************/ #ifdef __cplusplus } /* end of extern "C" */ #endif /* For consistence: introduce prefixed macros */ #ifndef PBORI_FORCE_ORIGINAL_CUDD #define pbori_Cudd_IsConstant Cudd_IsConstant #define pbori_Cudd_Not Cudd_Not #define pbori_Cudd_NotCond Cudd_NotCond #define pbori_Cudd_Regular Cudd_Regular #define pbori_Cudd_Complement Cudd_Complement #define pbori_Cudd_IsComplement Cudd_IsComplement #define pbori_Cudd_T Cudd_T #define pbori_Cudd_E Cudd_E #define pbori_Cudd_V Cudd_V #define pbori_Cudd_ReadIndex Cudd_ReadIndex #define pbori_Cudd_ForeachCube Cudd_ForeachCube #define pbori_Cudd_ForeachPrime Cudd_ForeachPrime #define pbori_Cudd_ForeachNode Cudd_ForeachNode #define pbori_Cudd_zddForeachPath Cudd_zddForeachPath #endif #endif /* _CUDD */ BRiAl-1.2.0/cudd/cuddAPI.c 0000664 0000000 0000000 00000417740 13173454145 0015023 0 ustar 00root root 0000000 0000000 /**CFile*********************************************************************** FileName [cuddAPI.c] PackageName [cudd] Synopsis [Application interface functions.] Description [External procedures included in this module:
M
be the
ratio of the two numbers. For the purpose of realignment, the ZDD
variables from M*i
to (M+1)*i-1
are
reagarded as corresponding to BDD variable i
. 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 M
be the
ratio of the two numbers. For the purpose of realignment, the ZDD
variables from M*i
to (M+1)*i-1
are
reagarded as corresponding to BDD variable i
. 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 i
.]
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) {
unsigned 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.]
SideEffects [None]
SeeAlso [Cudd_ReadMaxCacheHard]
******************************************************************************/
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) {
unsigned 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 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]
******************************************************************************/
unsigned int
Cudd_ReadReorderings(
DdManager * dd)
{
return(dd->reorderings);
} /* end of Cudd_ReadReorderings */
/**Function********************************************************************
Synopsis [Returns the maximum number of times reordering may be invoked.]
Description [Returns the maximum number of times reordering may be invoked in
this manager.]
SideEffects [None]
SeeAlso [Cudd_ReadReorderings Cudd_SetMaxReorderings Cudd_ReduceHeap]
******************************************************************************/
unsigned int
Cudd_ReadMaxReorderings(
DdManager * dd)
{
return(dd->maxReorderings);
} /* end of Cudd_ReadMaxReorderings */
/**Function********************************************************************
Synopsis [Sets the maximum number of times reordering may be invoked.]
Description [Sets the maximum number of times reordering may be invoked in
this manager. The default value is (practically) infinite.]
SideEffects [None]
SeeAlso [Cudd_ReadReorderings Cudd_ReadMaxReorderings Cudd_ReduceHeap]
******************************************************************************/
void
Cudd_SetMaxReorderings(
DdManager * dd, unsigned int mr)
{
dd->maxReorderings = mr;
} /* end of Cudd_SetMaxReorderings */
/**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]
******************************************************************************/
#ifdef PBORI_FORCE_ORIGINAL_CUDD
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 */
#endif
/**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 f10 = f01
or
f11 = f00
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 f10 = f01
or
f11 = f00
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 y
not coming from x
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 y
not coming from x
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 order randomization factor.]
Description [Returns the order randomization factor. If non-zero this
factor is used to determine a perturbation of the next reordering threshold.
Larger factors cause larger perturbations.]
SideEffects [None]
SeeAlso [Cudd_SetOrderRandomization]
******************************************************************************/
unsigned int
Cudd_ReadOrderRandomization(
DdManager * dd)
{
return(dd->randomizeOrder);
} /* end of Cudd_ReadOrderRandomization */
/**Function********************************************************************
Synopsis [Sets the order randomization factor.]
Description []
SideEffects [None]
SeeAlso [Cudd_ReadOrderRandomization]
******************************************************************************/
void
Cudd_SetOrderRandomization(
DdManager * dd,
unsigned int factor)
{
dd->randomizeOrder = factor;
} /* end of Cudd_SetOrderRandomization */
/**Function********************************************************************
Synopsis [Returns the memory in use by the manager measured in bytes.]
Description []
SideEffects [None]
SeeAlso []
******************************************************************************/
unsigned 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",
(int) 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",
(int) 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",
(int) 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: %lu\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);
#ifdef 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
#ifdef 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);
#ifdef 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.]
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 = (long) (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((long)(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,
DD_HFP f,
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,
DD_HFP f,
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,
DD_HFP f,
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,
const 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,
const char *str,
void *data)
{
unsigned long initialTime = (long) data;
int retval;
unsigned 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 [Hook function to print the current variable order.]
Description [Hook function to print the current variable order. It may be
called before or after reordering. Prints on the manager's stdout a
parenthesized list that describes the variable groups.
Returns 1 if successful; 0 otherwise.]
SideEffects [None]
SeeAlso [Cudd_StdPreReordHook]
******************************************************************************/
#ifdef PBORI_FORCE_ORIGINAL_CUDD
int
Cudd_PrintGroupedOrder(
DdManager * dd,
const char *str,
void *data)
{
int isBdd = strcmp(str, "ZDD");
MtrNode *tree = isBdd ? dd->tree : dd->treeZ;
int *invperm = isBdd ? dd->invperm : dd->invpermZ;
int size = isBdd ? dd->size : dd->sizeZ;
if (tree == NULL) {
int i, retval;
for (i=0; i < size; i++) {
retval = fprintf(dd->out, "%c%d", i==0 ? '(' : ',', invperm[i]);
if (retval == EOF) return(0);
}
retval = fprintf(dd->out,")\n");
return (retval != EOF);
} else {
return Mtr_PrintGroupedOrder(tree,invperm,dd->out);
}
} /* end of Cudd_PrintGroupedOrder */
#endif
/**Function********************************************************************
Synopsis [Enables monitoring of ordering.]
Description [Enables monitoring of ordering.
Returns 1 if successful; 0 otherwise.]
SideEffects [Installs functions in the pre-reordering and post-reordering
hooks.]
SeeAlso [Cudd_EnableReorderingReporting]
******************************************************************************/
#ifdef PBORI_FORCE_ORIGINAL_CUDD
int
Cudd_EnableOrderingMonitoring(
DdManager *dd)
{
if (!Cudd_AddHook(dd, Cudd_PrintGroupedOrder, CUDD_PRE_REORDERING_HOOK)) {
return(0);
}
if (!Cudd_AddHook(dd, Cudd_StdPreReordHook, CUDD_PRE_REORDERING_HOOK)) {
return(0);
}
if (!Cudd_AddHook(dd, Cudd_StdPostReordHook, CUDD_POST_REORDERING_HOOK)) {
return(0);
}
if (!Cudd_AddHook(dd, Cudd_PrintGroupedOrder, CUDD_POST_REORDERING_HOOK)) {
return(0);
}
return(1);
} /* end of Cudd_EnableOrderingMonitoring */
/**Function********************************************************************
Synopsis [Disables monitoring of ordering.]
Description [Disables monitoring of ordering.
Returns 1 if successful; 0 otherwise.]
SideEffects [Removes functions from the pre-reordering and post-reordering
hooks.]
SeeAlso [Cudd_EnableOrderingMonitoring]
******************************************************************************/
int
Cudd_DisableOrderingMonitoring(
DdManager *dd)
{
if (!Cudd_RemoveHook(dd, Cudd_StdPreReordHook, CUDD_PRE_REORDERING_HOOK)) {
return(0);
}
if (!Cudd_RemoveHook(dd, Cudd_PrintGroupedOrder, CUDD_PRE_REORDERING_HOOK)) {
return(0);
}
if (!Cudd_RemoveHook(dd, Cudd_PrintGroupedOrder, CUDD_POST_REORDERING_HOOK)) {
return(0);
}
if (!Cudd_RemoveHook(dd, Cudd_StdPostReordHook, CUDD_POST_REORDERING_HOOK)) {
return(0);
}
return(1);
} /* end of Cudd_DisableOrderingMonitoring */
/**Function********************************************************************
Synopsis [Returns 1 if monitoring of ordering is enabled.]
Description [Returns 1 if monitoring of ordering is enabled;
0 otherwise.]
SideEffects [none]
SeeAlso [Cudd_EnableOrderingMonitoring Cudd_DisableOrderingMonitoring]
******************************************************************************/
int
Cudd_OrderingMonitoring(
DdManager *dd)
{
return(Cudd_IsInHook(dd, Cudd_PrintGroupedOrder, CUDD_PRE_REORDERING_HOOK));
} /* end of Cudd_OrderingMonitoring */
#endif
/**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]
******************************************************************************/
unsigned 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,
unsigned 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]
******************************************************************************/
#ifdef PBORI_FORCE_ORIGINAL_CUDD
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 */
#endif
BRiAl-1.2.0/cudd/cuddAddAbs.c 0000664 0000000 0000000 00000042240 13173454145 0015515 0 ustar 00root root 0000000 0000000 /**CFile***********************************************************************
FileName [cuddAddAbs.c]
PackageName [cudd]
Synopsis [Quantification functions for ADDs.]
Description [External procedures included in this module:
limit
, this function returns NULL.]
SideEffects [None]
SeeAlso [Cudd_bddAndAbstract]
******************************************************************************/
DdNode *
Cudd_bddAndAbstractLimit(
DdManager * manager,
DdNode * f,
DdNode * g,
DdNode * cube,
unsigned int limit)
{
DdNode *res;
unsigned int saveLimit = manager->maxLive;
manager->maxLive = (manager->keys - manager->dead) +
(manager->keysZ - manager->deadZ) + limit;
do {
manager->reordered = 0;
res = cuddBddAndAbstractRecur(manager, f, g, cube);
} while (manager->reordered == 1);
manager->maxLive = saveLimit;
return(res);
} /* end of Cudd_bddAndAbstractLimit */
/*---------------------------------------------------------------------------*/
/* 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 */
/*---------------------------------------------------------------------------*/
BRiAl-1.2.0/cudd/cuddAnneal.c 0000664 0000000 0000000 00000053710 13173454145 0015601 0 ustar 00root root 0000000 0000000 /**CFile***********************************************************************
FileName [cuddAnneal.c]
PackageName [cudd]
Synopsis [Reordering of DDs based on simulated annealing]
Description [Internal procedures included in this file:
dest
.]
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 sum
.]
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((DdApaDigit) 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
diff
.]
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 = DD_MSDIGIT(partial) + DD_APA_MASK + a[i] - b[i];
diff[i] = (DdApaDigit) DD_LSDIGIT(partial);
}
return((DdApaDigit) 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 quotient
.]
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 quotient
.]
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 in
.]
SideEffects [The result is returned in parameter b
.]
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 number
.]
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 number
.]
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);
FREE(first);
FREE(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] = (unsigned char) 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] = (unsigned char) 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 digits
.]
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:
|f'| = max - |f|
.
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, node, &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 */
BRiAl-1.2.0/cudd/cuddApprox.c 0000664 0000000 0000000 00000207433 13173454145 0015657 0 ustar 00root root 0000000 0000000 /**CFile***********************************************************************
FileName [cuddApprox.c]
PackageName [cudd]
Synopsis [Procedures to approximate a given BDD.]
Description [External procedures provided by this module:
limit
are
required.]
SideEffects [None]
SeeAlso [Cudd_bddExistAbstract]
******************************************************************************/
DdNode *
Cudd_bddExistAbstractLimit(
DdManager * manager,
DdNode * f,
DdNode * cube,
unsigned int limit)
{
DdNode *res;
unsigned int saveLimit = manager->maxLive;
if (bddCheckPositiveCube(manager, cube) == 0) {
(void) fprintf(manager->err,
"Error: Can only abstract positive cubes\n");
manager->errorCode = CUDD_INVALID_ARG;
return(NULL);
}
manager->maxLive = (manager->keys - manager->dead) +
(manager->keysZ - manager->deadZ) + limit;
do {
manager->reordered = 0;
res = cuddBddExistAbstractRecur(manager, f, cube);
} while (manager->reordered == 1);
manager->maxLive = saveLimit;
return(res);
} /* end of Cudd_bddExistAbstractLimit */
/**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;
DD_CTFP cacheOp;
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 = (DD_CTFP) 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 */
BRiAl-1.2.0/cudd/cuddBddCorr.c 0000664 0000000 0000000 00000034340 13173454145 0015720 0 ustar 00root root 0000000 0000000 /**CFile***********************************************************************
FileName [cuddBddCorr.c]
PackageName [cudd]
Synopsis [Correlation between BDDs.]
Description [External procedures included in this module:
limit
are
required.]
SideEffects [None]
SeeAlso [Cudd_bddIte]
******************************************************************************/
DdNode *
Cudd_bddIteLimit(
DdManager * dd,
DdNode * f,
DdNode * g,
DdNode * h,
unsigned int limit)
{
DdNode *res;
unsigned int saveLimit = dd->maxLive;
dd->maxLive = (dd->keys - dd->dead) + (dd->keysZ - dd->deadZ) + limit;
do {
dd->reordered = 0;
res = cuddBddIteRecur(dd,f,g,h);
} while (dd->reordered == 1);
dd->maxLive = saveLimit;
return(res);
} /* end of Cudd_bddIteLimit */
/**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 conjunction of two BDDs f and g. Returns
NULL if too many nodes are required.]
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 or more new nodes than limit
are
required.]
SideEffects [None]
SeeAlso [Cudd_bddAnd]
******************************************************************************/
DdNode *
Cudd_bddAndLimit(
DdManager * dd,
DdNode * f,
DdNode * g,
unsigned int limit)
{
DdNode *res;
unsigned int saveLimit = dd->maxLive;
dd->maxLive = (dd->keys - dd->dead) + (dd->keysZ - dd->deadZ) + limit;
do {
dd->reordered = 0;
res = cuddBddAndRecur(dd,f,g);
} while (dd->reordered == 1);
dd->maxLive = saveLimit;
return(res);
} /* end of Cudd_bddAndLimit */
/**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 disjunction of two BDDs f and g. Returns
NULL if too many nodes are required.]
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 or more new nodes than limit
are
required.]
SideEffects [None]
SeeAlso [Cudd_bddOr]
******************************************************************************/
DdNode *
Cudd_bddOrLimit(
DdManager * dd,
DdNode * f,
DdNode * g,
unsigned int limit)
{
DdNode *res;
unsigned int saveLimit = dd->maxLive;
dd->maxLive = (dd->keys - dd->dead) + (dd->keysZ - dd->deadZ) + limit;
do {
dd->reordered = 0;
res = cuddBddAndRecur(dd,Cudd_Not(f),Cudd_Not(g));
} while (dd->reordered == 1);
dd->maxLive = saveLimit;
res = Cudd_NotCond(res,res != NULL);
return(res);
} /* end of Cudd_bddOrLimit */
/**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 [Computes the exclusive NOR of two BDDs f and g. Returns
NULL if too many nodes are required.]
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 or more new nodes than limit
are
required.]
SideEffects [None]
SeeAlso [Cudd_bddXnor]
******************************************************************************/
DdNode *
Cudd_bddXnorLimit(
DdManager * dd,
DdNode * f,
DdNode * g,
unsigned int limit)
{
DdNode *res;
unsigned int saveLimit = dd->maxLive;
dd->maxLive = (dd->keys - dd->dead) + (dd->keysZ - dd->deadZ) + limit;
do {
dd->reordered = 0;
res = cuddBddXorRecur(dd,f,Cudd_Not(g));
} while (dd->reordered == 1);
dd->maxLive = saveLimit;
return(res);
} /* end of Cudd_bddXnorLimit */
/**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,(DD_CTFP)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,(DD_CTFP)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 */
BRiAl-1.2.0/cudd/cuddBridge.c 0000664 0000000 0000000 00000064070 13173454145 0015600 0 ustar 00root root 0000000 0000000 /**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:
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.
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 */ BRiAl-1.2.0/cudd/cuddDecomp.c 0000664 0000000 0000000 00000174721 13173454145 0015620 0 ustar 00root root 0000000 0000000 /**CFile*********************************************************************** FileName [cuddDecomp.c] PackageName [cudd] Synopsis [Functions for BDD decomposition.] Description [External procedures included in this file:
f
is the function of the BDD and
x
is the variable, the decomposition is
(f+x)(f+x')
. 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 f
is the function of the
BDD and x
is the variable, the decomposition is
f*x + f*x'
. 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, N, &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, node, &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, node, &dummy)) {
factors = dummy;
return(factors);
}
/* check distance and local reference count of this node */
N = Cudd_Regular(node);
if (!st_lookup(distanceTable, N, &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, Nv, &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, Nnv, &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 */
BRiAl-1.2.0/cudd/cuddEssent.c 0000664 0000000 0000000 00000127231 13173454145 0015644 0 ustar 00root root 0000000 0000000 /**CFile***********************************************************************
FileName [cuddEssent.c]
PackageName [cudd]
Synopsis [Functions for the detection of essential variables.]
Description [External procedures included in this file:
binomial(n,k) = n/k * binomial(n-1,k-1).Returns the computed value if successful; -1 if out of range.] SideEffects [None] SeeAlso [] ******************************************************************************/ static int getMaxBinomial( int n) { double i, j, result; if (n < 0 || n > 33) return(-1); /* error */ if (n < 2) return(1); for (result = (double)((n+3)/2), i = result+1, j=2; i <= n; i++, j++) { result *= i; result /= j; } return((int)result); } /* end of getMaxBinomial */ #if 0 /**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 */ #endif /**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) { FREE(matrix); 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; #if 0 int numvars; #endif int result; #ifdef DD_STATS unsigned 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 #if 0 numvars = table->size; (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:
f
of a function to be minimized and a BDD
c
representing the care set, Cudd_bddLICompaction
produces the BDD of a function that agrees with f
wherever c
is 1. Safe minimization means that the size
of the result is guaranteed not to exceed the size of
f
. 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
l
and u
, 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 f
over
c
.]
Description [Finds a small BDD that agrees with f
over
c
. 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 f
.]
Description [Finds a dense subset of BDD f
. 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_RemapUnderApprox 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,0.95);
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 f
.]
Description [Finds a dense superset of BDD f
. 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 [Implements the recursive step of Cudd_bddAnd.]
Description [Implements the recursive step of Cudd_bddNPAnd.
Returns a pointer to the result is successful; NULL otherwise.]
SideEffects [None]
SeeAlso [Cudd_bddNPAnd]
******************************************************************************/
DdNode *
cuddBddNPAndRecur(
DdManager * manager,
DdNode * f,
DdNode * g)
{
DdNode *F, *ft, *fe, *G, *gt, *ge;
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(one);
else return(Cudd_Not(one));
}
if (G == one) {
if (g == one) return(f);
else return(g);
}
if (F == one) {
return(f);
}
/* At this point f and g are not constant. */
/* Check cache. */
if (F->ref != 1 || G->ref != 1) {
r = cuddCacheLookup2(manager, Cudd_bddNPAnd, 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];
if (topg < topf) { /* abstract top variable from g */
DdNode *d;
/* Find complements of cofactors of g. */
if (Cudd_IsComplement(g)) {
gt = cuddT(G);
ge = cuddE(G);
} else {
gt = Cudd_Not(cuddT(g));
ge = Cudd_Not(cuddE(g));
}
/* Take the OR by applying DeMorgan. */
d = cuddBddAndRecur(manager, gt, ge);
if (d == NULL) return(NULL);
d = Cudd_Not(d);
cuddRef(d);
r = cuddBddNPAndRecur(manager, f, d);
if (r == NULL) {
Cudd_IterDerefBdd(manager, d);
return(NULL);
}
cuddRef(r);
Cudd_IterDerefBdd(manager, d);
cuddCacheInsert2(manager, Cudd_bddNPAnd, f, g, r);
cuddDeref(r);
return(r);
}
/* Compute cofactors. */
index = F->index;
ft = cuddT(F);
fe = cuddE(F);
if (Cudd_IsComplement(f)) {
ft = Cudd_Not(ft);
fe = Cudd_Not(fe);
}
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 = cuddBddAndRecur(manager, ft, gt);
if (t == NULL) return(NULL);
cuddRef(t);
e = cuddBddAndRecur(manager, fe, ge);
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_bddNPAnd, f, g, r);
return(r);
} /* end of cuddBddNPAndRecur */
/**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
f
of a function to be minimized and a BDD
c
representing the care set, Cudd_bddLICompaction
produces the BDD of a function that agrees with f
wherever c
is 1. Safe minimization means that the size
of the result is guaranteed not to exceed the size of
f
. 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 f
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 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_int(cache, (char *)key, &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) {
Fv = cuddT(f); Fnv = cuddE(f);
} else {
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;
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, f, &r)) {
return(Cudd_NotCond(r,comple));
}
/* Retrieve the edge markings. */
if (st_lookup_int(table, (char *)f, &markings) == 0)
return(NULL);
markT = markings >> 2;
markE = markings & 3;
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 */
BRiAl-1.2.0/cudd/cuddGenetic.c 0000664 0000000 0000000 00000066606 13173454145 0015771 0 ustar 00root root 0000000 0000000 /**CFile***********************************************************************
FileName [cuddGenetic.c]
PackageName [cudd]
Synopsis [Genetic algorithm for variable reordering.]
Description [Internal procedures included in this file:
x\[0\] y\[0\] x\[1\] y\[1\] ...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
node
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
node
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
node
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)(ptruint)(f) * DD_P1 + \
(unsigned)(ptruint)(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)(ptruint)(f) + (unsigned)(ptruint)(o)) * DD_P1 + \
(unsigned)(ptruint)(g)) * DD_P2 + \
(unsigned)(ptruint)(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)(ptruint)(f) + (unsigned)(ptruint)(o)) * DD_P1 + \
(unsigned)(ptruint)(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 (PBORI_PREFIX(DdManager) *manager, DdNode *f, DdNode *cube);
extern DdNode * cuddAddUnivAbstractRecur (PBORI_PREFIX(DdManager) *manager, DdNode *f, DdNode *cube);
extern DdNode * cuddAddOrAbstractRecur (PBORI_PREFIX(DdManager) *manager, DdNode *f, DdNode *cube);
extern DdNode * cuddAddApplyRecur (PBORI_PREFIX(DdManager) *dd, DdNode * (*)(PBORI_PREFIX(DdManager) *, DdNode **, DdNode **), DdNode *f, DdNode *g);
extern DdNode * cuddAddMonadicApplyRecur (PBORI_PREFIX(DdManager) * dd, DdNode * (*op)(PBORI_PREFIX(DdManager) *, DdNode *), DdNode * f);
extern DdNode * cuddAddScalarInverseRecur (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *epsilon);
extern DdNode * cuddAddIteRecur (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g, DdNode *h);
extern DdNode * cuddAddCmplRecur (PBORI_PREFIX(DdManager) *dd, DdNode *f);
extern DdNode * cuddAddNegateRecur (PBORI_PREFIX(DdManager) *dd, DdNode *f);
extern DdNode * cuddAddRoundOffRecur (PBORI_PREFIX(DdManager) *dd, DdNode *f, double trunc);
extern DdNode * cuddUnderApprox (PBORI_PREFIX(DdManager) *dd, DdNode *f, int numVars, int threshold, int safe, double quality);
extern DdNode * cuddRemapUnderApprox (PBORI_PREFIX(DdManager) *dd, DdNode *f, int numVars, int threshold, double quality);
extern DdNode * cuddBiasedUnderApprox (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *b, int numVars, int threshold, double quality1, double quality0);
extern DdNode * cuddBddAndAbstractRecur (PBORI_PREFIX(DdManager) *manager, DdNode *f, DdNode *g, DdNode *cube);
extern int cuddAnnealing (PBORI_PREFIX(DdManager) *table, int lower, int upper);
extern DdNode * cuddBddExistAbstractRecur (PBORI_PREFIX(DdManager) *manager, DdNode *f, DdNode *cube);
extern DdNode * cuddBddXorExistAbstractRecur (PBORI_PREFIX(DdManager) *manager, DdNode *f, DdNode *g, DdNode *cube);
extern DdNode * cuddBddBooleanDiffRecur (PBORI_PREFIX(DdManager) *manager, DdNode *f, DdNode *var);
extern DdNode * cuddBddIteRecur (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g, DdNode *h);
extern DdNode * cuddBddIntersectRecur (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g);
extern DdNode * cuddBddAndRecur (PBORI_PREFIX(DdManager) *manager, DdNode *f, DdNode *g);
extern DdNode * cuddBddXorRecur (PBORI_PREFIX(DdManager) *manager, DdNode *f, DdNode *g);
extern DdNode * cuddBddTransfer (PBORI_PREFIX(DdManager) *ddS, PBORI_PREFIX(DdManager) *ddD, DdNode *f);
extern DdNode * cuddAddBddDoPattern (PBORI_PREFIX(DdManager) *dd, DdNode *f);
extern int PBORI_PREFIX(cuddInitCache) (PBORI_PREFIX(DdManager) *unique, unsigned int cacheSize, unsigned int maxCacheSize);
extern void PBORI_PREFIX(cuddCacheInsert) (PBORI_PREFIX(DdManager) *table, ptruint op, DdNode *f, DdNode *g, DdNode *h, DdNode *data);
extern void PBORI_PREFIX(cuddCacheInsert2) (PBORI_PREFIX(DdManager) *table, DdNode * (*)(PBORI_PREFIX(DdManager) *, DdNode *, DdNode *), DdNode *f, DdNode *g, DdNode *data);
extern void PBORI_PREFIX(cuddCacheInsert1) (PBORI_PREFIX(DdManager) *table, DdNode * (*)(PBORI_PREFIX(DdManager) *, DdNode *), DdNode *f, DdNode *data);
extern DdNode * PBORI_PREFIX(cuddCacheLookup) (PBORI_PREFIX(DdManager) *table, ptruint op, DdNode *f, DdNode *g, DdNode *h);
extern DdNode * PBORI_PREFIX(cuddCacheLookupZdd) (PBORI_PREFIX(DdManager) *table, ptruint op, DdNode *f, DdNode *g, DdNode *h);
extern DdNode * PBORI_PREFIX(cuddCacheLookup2) (PBORI_PREFIX(DdManager) *table, DdNode * (*)(PBORI_PREFIX(DdManager) *, DdNode *, DdNode *), DdNode *f, DdNode *g);
extern DdNode * PBORI_PREFIX(cuddCacheLookup1) (PBORI_PREFIX(DdManager) *table, DdNode * (*)(PBORI_PREFIX(DdManager) *, DdNode *), DdNode *f);
extern DdNode * PBORI_PREFIX(cuddCacheLookup2Zdd) (PBORI_PREFIX(DdManager) *table, DdNode * (*)(PBORI_PREFIX(DdManager) *, DdNode *, DdNode *), DdNode *f, DdNode *g);
extern DdNode * PBORI_PREFIX(cuddCacheLookup1Zdd) (PBORI_PREFIX(DdManager) *table, DdNode * (*)(PBORI_PREFIX(DdManager) *, DdNode *), DdNode *f);
extern DdNode * PBORI_PREFIX(cuddConstantLookup) (PBORI_PREFIX(DdManager) *table, ptruint op, DdNode *f, DdNode *g, DdNode *h);
extern int PBORI_PREFIX(cuddCacheProfile) (PBORI_PREFIX(DdManager) *table, FILE *fp);
extern void PBORI_PREFIX(cuddCacheResize) (PBORI_PREFIX(DdManager) *table);
extern void PBORI_PREFIX(cuddCacheFlush) (PBORI_PREFIX(DdManager) *table);
extern int PBORI_PREFIX(cuddComputeFloorLog2) (unsigned int value);
extern int cuddHeapProfile (PBORI_PREFIX(DdManager) *dd);
extern void cuddPrintNode (DdNode *f, FILE *fp);
#ifdef PBORI_FORCE_ORIGINAL_CUDD
extern void cuddPrintVarGroups (PBORI_PREFIX(DdManager) * dd, MtrNode * root, int zdd, int
silent);
#endif
extern DdNode * cuddBddClippingAnd (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g, int maxDepth, int direction);
extern DdNode * cuddBddClippingAndAbstract (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g, DdNode *cube, int maxDepth, int direction);
extern void cuddGetBranches (DdNode *g, DdNode **g1, DdNode **g0);
extern DdNode * cuddCofactorRecur (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g);
extern DdNode * cuddBddComposeRecur (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g, DdNode *proj);
extern DdNode * cuddAddComposeRecur (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g, DdNode *proj);
extern int cuddExact (PBORI_PREFIX(DdManager) *table, int lower, int upper);
extern DdNode * cuddBddConstrainRecur (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *c);
extern DdNode * cuddBddRestrictRecur (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *c);
extern DdNode * cuddBddNPAndRecur (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *c);
extern DdNode * cuddAddConstrainRecur (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *c);
extern DdNode * cuddAddRestrictRecur (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *c);
extern DdNode * cuddBddLICompaction (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *c);
extern int cuddGa (PBORI_PREFIX(DdManager) *table, int lower, int upper);
extern int cuddTreeSifting (PBORI_PREFIX(DdManager) *table, Cudd_ReorderingType method);
extern int PBORI_PREFIX(cuddZddInitUniv) (PBORI_PREFIX(DdManager) *zdd);
extern void PBORI_PREFIX(cuddZddFreeUniv) (PBORI_PREFIX(DdManager) *zdd);
extern void cuddSetInteract (PBORI_PREFIX(DdManager) *table, int x, int y);
extern int cuddTestInteract (PBORI_PREFIX(DdManager) *table, int x, int y);
extern int cuddInitInteract (PBORI_PREFIX(DdManager) *table);
extern DdLocalCache * PBORI_PREFIX(cuddLocalCacheInit) (PBORI_PREFIX(DdManager) *manager, unsigned int keySize, unsigned int cacheSize, unsigned int maxCacheSize);
extern void PBORI_PREFIX(cuddLocalCacheQuit) (DdLocalCache *cache);
extern void PBORI_PREFIX(cuddLocalCacheInsert) (DdLocalCache *cache, DdNodePtr *key, DdNode *value);
extern DdNode * PBORI_PREFIX(cuddLocalCacheLookup) (DdLocalCache *cache, DdNodePtr *key);
extern void PBORI_PREFIX(cuddLocalCacheClearDead) (PBORI_PREFIX(DdManager) *manager);
extern int PBORI_PREFIX(cuddIsInDeathRow) (PBORI_PREFIX(DdManager) *dd, DdNode *f);
extern int PBORI_PREFIX(cuddTimesInDeathRow) (PBORI_PREFIX(DdManager) *dd, DdNode *f);
extern void PBORI_PREFIX(cuddLocalCacheClearAll) (PBORI_PREFIX(DdManager) *manager);
#ifdef DD_CACHE_PROFILE
extern int cuddLocalCacheProfile (DdLocalCache *cache);
#endif
extern DdHashTable * PBORI_PREFIX(cuddHashTableInit) (PBORI_PREFIX(DdManager) *manager, unsigned int keySize, unsigned int initSize);
extern void PBORI_PREFIX(cuddHashTableQuit) (DdHashTable *hash);
extern void PBORI_PREFIX(cuddHashTableGenericQuit) (DdHashTable *hash);
extern int PBORI_PREFIX(cuddHashTableInsert) (DdHashTable *hash, DdNodePtr *key, DdNode *value, ptrint count);
extern DdNode * PBORI_PREFIX(cuddHashTableLookup) (DdHashTable *hash, DdNodePtr *key);
extern int PBORI_PREFIX(cuddHashTableInsert1) (DdHashTable *hash, DdNode *f, DdNode *value, ptrint count);
extern DdNode * PBORI_PREFIX(cuddHashTableLookup1) (DdHashTable *hash, DdNode *f);
extern int PBORI_PREFIX(cuddHashTableInsert2) (DdHashTable *hash, DdNode *f, DdNode *g, DdNode *value, ptrint count);
extern DdNode * PBORI_PREFIX(cuddHashTableLookup2) (DdHashTable *hash, DdNode *f, DdNode *g);
extern int PBORI_PREFIX(cuddHashTableInsert3) (DdHashTable *hash, DdNode *f, DdNode *g, DdNode *h, DdNode *value, ptrint count);
extern DdNode * PBORI_PREFIX(cuddHashTableLookup3) (DdHashTable *hash, DdNode *f, DdNode *g, DdNode *h);
extern int PBORI_PREFIX(cuddHashTableGenericInsert)(DdHashTable * hash, DdNode * f, void * value);
extern void * PBORI_PREFIX(cuddHashTableGenericLookup)(DdHashTable * hash, DdNode * f);
extern DdLevelQueue * cuddLevelQueueInit (int levels, int itemSize, int numBuckets);
extern void cuddLevelQueueQuit (DdLevelQueue *queue);
extern void * cuddLevelQueueFirst(DdLevelQueue * queue, void * key, int level);
extern void * cuddLevelQueueEnqueue (DdLevelQueue *queue, void *key, int level);
extern void cuddLevelQueueDequeue (DdLevelQueue *queue, int level);
extern int cuddLinearAndSifting (PBORI_PREFIX(DdManager) *table, int lower, int upper);
extern int cuddLinearInPlace (PBORI_PREFIX(DdManager) * table, int x, int y);
extern void cuddUpdateInteractionMatrix (PBORI_PREFIX(DdManager) * table, int xindex, int yindex);
extern int cuddInitLinear (PBORI_PREFIX(DdManager) *table);
extern int cuddResizeLinear (PBORI_PREFIX(DdManager) *table);
extern DdNode * cuddBddLiteralSetIntersectionRecur (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g);
extern DdNode * cuddCProjectionRecur (PBORI_PREFIX(DdManager) *dd, DdNode *R, DdNode *Y, DdNode *Ysupp);
extern DdNode * cuddBddClosestCube (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g, CUDD_VALUE_TYPE bound);
extern void PBORI_PREFIX(cuddReclaim) (PBORI_PREFIX(DdManager) *table, DdNode *n);
extern void PBORI_PREFIX(cuddReclaimZdd) (PBORI_PREFIX(DdManager) *table, DdNode *n);
extern void PBORI_PREFIX(cuddClearDeathRow) (PBORI_PREFIX(DdManager) *table);
extern void PBORI_PREFIX(cuddShrinkDeathRow) (PBORI_PREFIX(DdManager) *table);
extern DdNode * cuddDynamicAllocNode (PBORI_PREFIX(DdManager) *table);
extern int cuddSifting (PBORI_PREFIX(DdManager) *table, int lower, int upper);
extern int cuddSwapping (PBORI_PREFIX(DdManager) *table, int lower, int upper, Cudd_ReorderingType heuristic);
#ifdef PBORI_FORCE_ORIGINAL_CUDD
extern int cuddNextHigh (PBORI_PREFIX(DdManager) *table, int x);
extern int cuddNextLow (PBORI_PREFIX(DdManager) *table, int x);
#endif
extern int cuddSwapInPlace (PBORI_PREFIX(DdManager) *table, int x, int y);
extern int cuddBddAlignToZdd (PBORI_PREFIX(DdManager) *table);
extern DdNode * cuddBddMakePrime (PBORI_PREFIX(DdManager) *dd, DdNode *cube, DdNode *f);
extern DdNode * cuddSolveEqnRecur (PBORI_PREFIX(DdManager) *bdd, DdNode *F, DdNode *Y, DdNode **G, int n, int *yIndex, int i);
extern DdNode * cuddVerifySol (PBORI_PREFIX(DdManager) *bdd, DdNode *F, DdNode **G, int *yIndex, int n);
#ifdef ST_INCLUDED
extern DdNode* cuddSplitSetRecur (PBORI_PREFIX(DdManager) *manager, st_table *mtable, int *varSeen, DdNode *p, double n, double max, int index);
#endif
extern DdNode * cuddSubsetHeavyBranch (PBORI_PREFIX(DdManager) *dd, DdNode *f, int numVars, int threshold);
extern DdNode * cuddSubsetShortPaths (PBORI_PREFIX(DdManager) *dd, DdNode *f, int numVars, int threshold, int hardlimit);
extern int cuddSymmCheck (PBORI_PREFIX(DdManager) *table, int x, int y);
extern int cuddSymmSifting (PBORI_PREFIX(DdManager) *table, int lower, int upper);
extern int cuddSymmSiftingConv (PBORI_PREFIX(DdManager) *table, int lower, int upper);
extern DdNode * PBORI_PREFIX(cuddAllocNode) (PBORI_PREFIX(DdManager) *unique);
extern PBORI_PREFIX(DdManager) * PBORI_PREFIX(cuddInitTable) (unsigned int numVars, unsigned int numVarsZ, unsigned int numSlots, unsigned int looseUpTo);
extern void PBORI_PREFIX(cuddFreeTable) (PBORI_PREFIX(DdManager) *unique);
extern int PBORI_PREFIX(cuddGarbageCollect) (PBORI_PREFIX(DdManager) *unique, int clearCache);
extern DdNode * PBORI_PREFIX(cuddUniqueInter) (PBORI_PREFIX(DdManager) *unique, int index, DdNode *T, DdNode *E);
extern DdNode * PBORI_PREFIX(cuddUniqueInterIVO) (PBORI_PREFIX(DdManager) *unique, int index, DdNode *T, DdNode *E);
extern DdNode * PBORI_PREFIX(cuddUniqueInterZdd) (PBORI_PREFIX(DdManager) *unique, int index, DdNode *T, DdNode *E);
extern DdNode * PBORI_PREFIX(cuddUniqueConst) (PBORI_PREFIX(DdManager) *unique, CUDD_VALUE_TYPE value);
#ifdef PBORI_FORCE_ORIGINAL_CUDD
extern DdNode * cuddZddGetNode (PBORI_PREFIX(DdManager) *zdd, int id, DdNode *T, DdNode *E);
#else
static inline DdNode *
PBORI_PREFIX(cuddZddGetNode) (
PBORI_PREFIX(DdManager) * zdd,
int id,
DdNode * T,
DdNode * E)
{
DdNode *node;
if (T == DD_ZERO(zdd))
return(E);
node = PBORI_PREFIX(cuddUniqueInterZdd)(zdd, id, T, E);
return(node);
}
#endif
extern DdNode * cuddZddGetNodeIVO (PBORI_PREFIX(DdManager) *dd, int index, DdNode *g, DdNode *h);
extern void PBORI_PREFIX(cuddRehash) (PBORI_PREFIX(DdManager) *unique, int i);
extern void cuddShrinkSubtable (PBORI_PREFIX(DdManager) *unique, int i);
extern int cuddInsertSubtables (PBORI_PREFIX(DdManager) *unique, int n, int level);
extern int cuddDestroySubtables (PBORI_PREFIX(DdManager) *unique, int n);
extern int PBORI_PREFIX(cuddResizeTableZdd) (PBORI_PREFIX(DdManager) *unique, int index);
extern void PBORI_PREFIX(cuddSlowTableGrowth) (PBORI_PREFIX(DdManager) *unique);
extern int cuddP (PBORI_PREFIX(DdManager) *dd, DdNode *f);
#ifdef ST_INCLUDED
extern enum st_retval cuddStCountfree (char *key, char *value, char *arg);
extern int cuddCollectNodes (DdNode *f, st_table *visited);
#endif
extern DdNodePtr * cuddNodeArray (DdNode *f, int *n);
extern int cuddWindowReorder (PBORI_PREFIX(DdManager) *table, int low, int high, Cudd_ReorderingType submethod);
extern DdNode * PBORI_PREFIX(cuddZddProduct) (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g);
extern DdNode * PBORI_PREFIX(cuddZddUnateProduct) (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g);
extern DdNode * PBORI_PREFIX(cuddZddWeakDiv) (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g);
extern DdNode * PBORI_PREFIX(cuddZddWeakDivF) (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g);
extern DdNode * PBORI_PREFIX(cuddZddDivide) (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g);
extern DdNode * PBORI_PREFIX(cuddZddDivideF) (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g);
extern int PBORI_PREFIX(cuddZddGetCofactors3) (PBORI_PREFIX(DdManager) *dd, DdNode *f, int v, DdNode **f1, DdNode **f0, DdNode **fd);
extern int PBORI_PREFIX(cuddZddGetCofactors2) (PBORI_PREFIX(DdManager) *dd, DdNode *f, int v, DdNode **f1, DdNode **f0);
extern DdNode * cuddZddComplement (PBORI_PREFIX(DdManager) *dd, DdNode *node);
extern int PBORI_PREFIX(cuddZddGetPosVarIndex)(PBORI_PREFIX(DdManager) * dd, int index);
extern int PBORI_PREFIX(cuddZddGetNegVarIndex)(PBORI_PREFIX(DdManager) * dd, int index);
extern int PBORI_PREFIX(cuddZddGetPosVarLevel)(PBORI_PREFIX(DdManager) * dd, int index);
extern int PBORI_PREFIX(cuddZddGetNegVarLevel)(PBORI_PREFIX(DdManager) * dd, int index);
extern int cuddZddTreeSifting (PBORI_PREFIX(DdManager) *table, Cudd_ReorderingType method);
extern DdNode * cuddZddIsop (PBORI_PREFIX(DdManager) *dd, DdNode *L, DdNode *U, DdNode **zdd_I);
extern DdNode * cuddBddIsop (PBORI_PREFIX(DdManager) *dd, DdNode *L, DdNode *U);
extern DdNode * cuddMakeBddFromZddCover (PBORI_PREFIX(DdManager) *dd, DdNode *node);
extern int cuddZddLinearSifting (PBORI_PREFIX(DdManager) *table, int lower, int upper);
extern int cuddZddAlignToBdd (PBORI_PREFIX(DdManager) *table);
#ifdef PBORI_FORCE_ORIGINAL_CUDD
extern int cuddZddNextHigh (PBORI_PREFIX(DdManager) *table, int x);
extern int cuddZddNextLow (PBORI_PREFIX(DdManager) *table, int x);
#endif
extern int cuddZddUniqueCompare (int *ptr_x, int *ptr_y);
extern int cuddZddSwapInPlace (PBORI_PREFIX(DdManager) *table, int x, int y);
extern int cuddZddSwapping (PBORI_PREFIX(DdManager) *table, int lower, int upper, Cudd_ReorderingType heuristic);
extern int cuddZddSifting (PBORI_PREFIX(DdManager) *table, int lower, int upper);
extern DdNode * PBORI_PREFIX(cuddZddIte) (PBORI_PREFIX(DdManager) *dd, DdNode *f, DdNode *g, DdNode *h);
extern DdNode * PBORI_PREFIX(cuddZddUnion) (PBORI_PREFIX(DdManager) *zdd, DdNode *P, DdNode *Q);
extern DdNode * PBORI_PREFIX(cuddZddIntersect) (PBORI_PREFIX(DdManager) *zdd, DdNode *P, DdNode *Q);
extern DdNode * PBORI_PREFIX(cuddZddDiff) (PBORI_PREFIX(DdManager) *zdd, DdNode *P, DdNode *Q);
extern DdNode * PBORI_PREFIX(cuddZddChangeAux) (PBORI_PREFIX(DdManager) *zdd, DdNode *P, DdNode *zvar);
extern DdNode * PBORI_PREFIX(cuddZddSubset1) (PBORI_PREFIX(DdManager) *dd, DdNode *P, int var);
extern DdNode * PBORI_PREFIX(cuddZddSubset0) (PBORI_PREFIX(DdManager) *dd, DdNode *P, int var);
extern DdNode * PBORI_PREFIX(cuddZddChange) (PBORI_PREFIX(DdManager) *dd, DdNode *P, int var);
extern int cuddZddSymmCheck (PBORI_PREFIX(DdManager) *table, int x, int y);
extern int cuddZddSymmSifting (PBORI_PREFIX(DdManager) *table, int lower, int upper);
extern int cuddZddSymmSiftingConv (PBORI_PREFIX(DdManager) *table, int lower, int upper);
extern int cuddZddP (PBORI_PREFIX(DdManager) *zdd, DdNode *f);
/**AutomaticEnd***************************************************************/
#ifdef __cplusplus
} /* end of extern "C" */
#endif
#ifndef PBORI_FORCE_ORIGINAL_CUDD
#define Cudd_OutOfMem MMout_of_memory
#endif
/* For consistence: introduce prefixed macros */
#ifndef PBORI_FORCE_ORIGINAL_CUDD
#define pbori_cuddIsConstant cuddIsConstant
#define pbori_cuddNot cuddNot
#define pbori_cuddNotCond cuddNotCond
#define pbori_cuddRegular cuddRegular
#define pbori_cuddT cuddT
#define pbori_cuddE cuddE
#define pbori_cuddV cuddV
#endif
#endif /* _CUDDINT */
BRiAl-1.2.0/cudd/cuddInteract.c 0000664 0000000 0000000 00000031306 13173454145 0016151 0 ustar 00root root 0000000 0000000 /**CFile***********************************************************************
FileName [cuddInteract.c]
PackageName [cudd]
Synopsis [Functions to manipulate the variable interaction matrix.]
Description [Internal procedures included in this file:
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
interact, but that for a given variable order have no arc connecting
their layers when they are adjacent. For instance, in ite(a,b,c) with
the order asize,
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;
unsigned long words;
long *interact;
char *support;
DdNode *f;
DdNode *sentinel = &(table->sentinel);
DdNodePtr *nodelist;
int slots;
unsigned long n = (unsigned long) 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(char,n);
if (support == NULL) {
table->errorCode = CUDD_MEMORY_OUT;
FREE(interact);
return(0);
}
for (i = 0; i < n; i++) {
support[i] = 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)) {
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,
char * 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 [Clears support.]
SeeAlso []
******************************************************************************/
static void
ddUpdateInteract(
DdManager * table,
char * support)
{
int i,j;
int n = table->size;
for (i = 0; i < n-1; i++) {
if (support[i] == 1) {
support[i] = 0;
for (j = i+1; j < n; j++) {
if (support[j] == 1) {
cuddSetInteract(table,i,j);
}
}
}
}
support[n-1] = 0;
} /* 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 */
BRiAl-1.2.0/cudd/cuddLCache.c 0000664 0000000 0000000 00000121025 13173454145 0015515 0 ustar 00root root 0000000 0000000 /**CFile***********************************************************************
FileName [cuddLCache.c]
PackageName [cudd]
Synopsis [Functions for local caches.]
Description [Internal procedures included in this module:
However, we do not use
When we compute
Another important observation concerns the need of examining all
four pairs of cofators only when both
Suppose
An 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,(DD_CTFP) 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);
if (minD <= CUDD_CONST_INDEX) 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;
}
if (minD <= CUDD_CONST_INDEX) 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) {
#ifdef DD_DEBUG
assert(topf == topg);
#endif
res = createResult(dd,index,1,cte,dte);
} else {
#ifdef DD_DEBUG
assert(topf == topg);
#endif
res = createResult(dd,index,0,cet,det);
}
if (res == NULL) {
Cudd_RecursiveDeref(dd, ctt);
Cudd_RecursiveDeref(dd, cee);
Cudd_RecursiveDeref(dd, cte);
Cudd_RecursiveDeref(dd, cet);
return(NULL);
}
cuddRef(res);
Cudd_RecursiveDeref(dd, ctt);
Cudd_RecursiveDeref(dd, cee);
Cudd_RecursiveDeref(dd, cte);
Cudd_RecursiveDeref(dd, cet);
/* Only cache results that are different from azero to avoid
** storing results that depend on the value of the bound. */
if ((F->ref != 1 || G->ref != 1) && res != azero)
cuddCacheInsert2(dd,(DD_CTFP) 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:
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.
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.
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.
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.
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 */
/*---------------------------------------------------------------------------*/
BRiAl-1.2.0/cudd/cuddRef.c 0000664 0000000 0000000 00000050546 13173454145 0015123 0 ustar 00root root 0000000 0000000 /**CFile***********************************************************************
FileName [cuddRef.c]
PackageName [cudd]
Synopsis [Functions that manipulate the reference counts.]
Description [External procedures included in this module:
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
unsigned 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;
if (table->randomizeOrder != 0) {
table->nextDyn += Cudd_Random() & table->randomizeOrder;
}
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 DD_OOMFP MMoutOfMemory;
DD_OOMFP saveHandler;
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 = - (int) (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 = %lu\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].ref = 0;
list[i - 1].next = &list[i];
} while (++i < DD_MEM_CHUNK);
list[DD_MEM_CHUNK-1].ref = 0;
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.
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.
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(DdNodePtr, 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 */
#ifdef PBORI_FORCE_ORIGINAL_CUDD
/**Function********************************************************************
Synopsis [Finds the first prime of a Boolean function.]
Description [Defines an iterator on a pair of BDDs describing a
(possibly incompletely specified) Boolean functions and finds the
first cube of a cover of the function. Returns a generator
that contains the information necessary to continue the enumeration
if successful; NULL otherwise.
The two argument BDDs are the lower and upper bounds of an interval.
It is a mistake to call this function with a lower bound that is not
less than or equal to the upper bound.
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 prime and irredundant cover of the function associated
with the two BDDs. The size of the array equals the number of
variables in the manager at the time Cudd_FirstCube is called.
This iterator can only be used on BDDs.]
SideEffects [The first cube is returned as side effect.]
SeeAlso [Cudd_ForeachPrime Cudd_NextPrime Cudd_GenFree Cudd_IsGenEmpty
Cudd_FirstCube Cudd_FirstNode]
******************************************************************************/
DdGen *
Cudd_FirstPrime(
DdManager *dd,
DdNode *l,
DdNode *u,
int **cube)
{
DdGen *gen;
DdNode *implicant, *prime, *tmp;
int length, result;
/* Sanity Check. */
if (dd == NULL || l == NULL || u == 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_PRIMES;
gen->status = CUDD_GEN_EMPTY;
gen->gen.primes.cube = NULL;
gen->gen.primes.ub = u;
gen->stack.sp = 0;
gen->stack.stack = NULL;
gen->node = l;
cuddRef(l);
gen->gen.primes.cube = ALLOC(int,dd->size);
if (gen->gen.primes.cube == NULL) {
dd->errorCode = CUDD_MEMORY_OUT;
FREE(gen);
return(NULL);
}
if (gen->node == Cudd_ReadLogicZero(dd)) {
gen->status = CUDD_GEN_EMPTY;
} else {
implicant = Cudd_LargestCube(dd,gen->node,&length);
if (implicant == NULL) {
Cudd_RecursiveDeref(dd,gen->node);
FREE(gen->gen.primes.cube);
FREE(gen);
return(NULL);
}
cuddRef(implicant);
prime = Cudd_bddMakePrime(dd,implicant,gen->gen.primes.ub);
if (prime == NULL) {
Cudd_RecursiveDeref(dd,gen->node);
Cudd_RecursiveDeref(dd,implicant);
FREE(gen->gen.primes.cube);
FREE(gen);
return(NULL);
}
cuddRef(prime);
Cudd_RecursiveDeref(dd,implicant);
tmp = Cudd_bddAnd(dd,gen->node,Cudd_Not(prime));
if (tmp == NULL) {
Cudd_RecursiveDeref(dd,gen->node);
Cudd_RecursiveDeref(dd,prime);
FREE(gen->gen.primes.cube);
FREE(gen);
return(NULL);
}
cuddRef(tmp);
Cudd_RecursiveDeref(dd,gen->node);
gen->node = tmp;
result = Cudd_BddToCubeArray(dd,prime,gen->gen.primes.cube);
if (result == 0) {
Cudd_RecursiveDeref(dd,gen->node);
Cudd_RecursiveDeref(dd,prime);
FREE(gen->gen.primes.cube);
FREE(gen);
return(NULL);
}
Cudd_RecursiveDeref(dd,prime);
gen->status = CUDD_GEN_NONEMPTY;
}
*cube = gen->gen.primes.cube;
return(gen);
} /* end of Cudd_FirstPrime */
#endif
#ifdef PBORI_FORCE_ORIGINAL_CUDD
/**Function********************************************************************
Synopsis [Generates the next prime of a Boolean function.]
Description [Generates the next cube of a Boolean function,
using generator gen. Returns 0 if the enumeration is completed; 1
otherwise.]
SideEffects [The cube and is returned as side effects. The
generator is modified.]
SeeAlso [Cudd_ForeachPrime Cudd_FirstPrime Cudd_GenFree Cudd_IsGenEmpty
Cudd_NextCube Cudd_NextNode]
******************************************************************************/
int
Cudd_NextPrime(
DdGen *gen,
int **cube)
{
DdNode *implicant, *prime, *tmp;
DdManager *dd = gen->manager;
int length, result;
if (gen->node == Cudd_ReadLogicZero(dd)) {
gen->status = CUDD_GEN_EMPTY;
} else {
implicant = Cudd_LargestCube(dd,gen->node,&length);
if (implicant == NULL) {
gen->status = CUDD_GEN_EMPTY;
return(0);
}
cuddRef(implicant);
prime = Cudd_bddMakePrime(dd,implicant,gen->gen.primes.ub);
if (prime == NULL) {
Cudd_RecursiveDeref(dd,implicant);
gen->status = CUDD_GEN_EMPTY;
return(0);
}
cuddRef(prime);
Cudd_RecursiveDeref(dd,implicant);
tmp = Cudd_bddAnd(dd,gen->node,Cudd_Not(prime));
if (tmp == NULL) {
Cudd_RecursiveDeref(dd,prime);
gen->status = CUDD_GEN_EMPTY;
return(0);
}
cuddRef(tmp);
Cudd_RecursiveDeref(dd,gen->node);
gen->node = tmp;
result = Cudd_BddToCubeArray(dd,prime,gen->gen.primes.cube);
if (result == 0) {
Cudd_RecursiveDeref(dd,prime);
gen->status = CUDD_GEN_EMPTY;
return(0);
}
Cudd_RecursiveDeref(dd,prime);
gen->status = CUDD_GEN_NONEMPTY;
}
if (gen->status == CUDD_GEN_EMPTY) return(0);
*cube = gen->gen.primes.cube;
return(1);
} /* end of Cudd_NextPrime */
#endif
#ifdef PBORI_FORCE_ORIGINAL_CUDD
/**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 */
#endif
#ifdef PBORI_FORCE_ORIGINAL_CUDD
/**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 */
#endif
#ifdef PBORI_FORCE_ORIGINAL_CUDD
/**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 */
#endif
#ifdef PBORI_FORCE_ORIGINAL_CUDD
/**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 */
#endif
/**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. The nodes are enumerated in a reverse topological
order, so that a node is always preceded in the enumeration by its
descendants.]
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 size;
/* 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->stack.sp = 0;
gen->node = NULL;
/* Collect all the nodes on the generator stack for later perusal. */
gen->stack.stack = cuddNodeArray(Cudd_Regular(f), &size);
if (gen->stack.stack == NULL) {
FREE(gen);
dd->errorCode = CUDD_MEMORY_OUT;
return(NULL);
}
gen->gen.nodes.size = size;
/* Find the first node. */
if (gen->stack.sp < gen->gen.nodes.size) {
gen->status = CUDD_GEN_NONEMPTY;
gen->node = gen->stack.stack[gen->stack.sp];
*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)
{
/* Find the next node. */
gen->stack.sp++;
if (gen->stack.sp < gen->gen.nodes.size) {
gen->node = gen->stack.stack[gen->stack.sp];
*node = gen->node;
return(1);
} else {
gen->status = CUDD_GEN_EMPTY;
return(0);
}
} /* 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_PRIMES:
FREE(gen->gen.primes.cube);
Cudd_RecursiveDeref(gen->manager,gen->node);
break;
case CUDD_GEN_NODES:
FREE(gen->stack.stack);
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 */
#ifdef PBORI_FORCE_ORIGINAL_CUDD
/**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 */
#endif
/**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 != sentinel) {
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(void)
{
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 DD 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 */
/**Function********************************************************************
Synopsis [Recursively collects all the nodes of a DD in an array.]
Description [Traverses the DD f and collects all its nodes in an array.
The caller should free the array returned by cuddNodeArray.
Returns a pointer to the array of nodes in case of success; NULL
otherwise. The nodes are collected in reverse topological order, so
that a node is always preceded in the array by all its descendants.]
SideEffects [The number of nodes is returned as a side effect.]
SeeAlso [Cudd_FirstNode]
******************************************************************************/
DdNodePtr *
cuddNodeArray(
DdNode *f,
int *n)
{
DdNodePtr *table;
int size, retval;
size = ddDagInt(Cudd_Regular(f));
table = ALLOC(DdNodePtr, size);
if (table == NULL) {
ddClearFlag(Cudd_Regular(f));
return(NULL);
}
retval = cuddNodeArrayRecur(f, table, 0);
assert(retval == size);
*n = size;
return(table);
} /* cuddNodeArray */
/*---------------------------------------------------------------------------*/
/* 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),
(ptruint) g / (ptruint) sizeof(DdNode),cuddV(g));
#else
(void) fprintf(dd->out,"ID = %c0x%x\tvalue = %-9g\n", bang(f),
(ptruint) g / (ptruint) 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),
(ptruint) g / (ptruint) sizeof(DdNode), g->index, g->ref);
#else
(void) fprintf(dd->out,"ID = %c0x%x\tindex = %d\tr = %d\t", bang(f),
(ptruint) g / (ptruint) sizeof(DdNode),g->index,g->ref);
#endif
#else
#if SIZEOF_VOID_P == 8
(void) fprintf(dd->out,"ID = %c0x%lx\tindex = %u\t", bang(f),
(ptruint) g / (ptruint) sizeof(DdNode),g->index);
#else
(void) fprintf(dd->out,"ID = %c0x%x\tindex = %hu\t", bang(f),
(ptruint) g / (ptruint) 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",(ptruint) n / (ptruint) sizeof(DdNode));
#else
(void) fprintf(dd->out,"T = 0x%x\t",(ptruint) n / (ptruint) 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), (ptruint) N/(ptruint) sizeof(DdNode));
#else
(void) fprintf(dd->out,"E = %c0x%x\n", bang(n), (ptruint) N/(ptruint) 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 cuddNodeArray.]
Description [Performs the recursive step of cuddNodeArray. Returns
an the number of nodes in the DD. Clear the least significant bit
of the next field that was used as visited flag by
cuddNodeArrayRecur when counting the nodes. node is supposed to be
regular; the invariant is maintained by this procedure.]
SideEffects [None]
SeeAlso []
******************************************************************************/
static int
cuddNodeArrayRecur(
DdNode *f,
DdNodePtr *table,
int index)
{
int tindex, eindex;
if (!Cudd_IsComplement(f->next)) {
return(index);
}
/* Clear visited flag. */
f->next = Cudd_Regular(f->next);
if (cuddIsConstant(f)) {
table[index] = f;
return(index + 1);
}
tindex = cuddNodeArrayRecur(cuddT(f), table, index);
eindex = cuddNodeArrayRecur(Cudd_Regular(cuddE(f)), table, tindex);
table[eindex] = f;
return(eindex + 1);
} /* end of cuddNodeArrayRecur */
/**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)) {
if (st_add_direct(table,(char *)node,(char *)node) ==
ST_OUT_OF_MEM)
return(CUDD_OUT_OF_MEM);
*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:
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
unsigned 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
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.
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(DdNodePtr, 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(Cudd_Regular(top))) {
/* Take the else branch first. */
gen->gen.cubes.cube[Cudd_Regular(top)->index] = 0;
next = cuddE(Cudd_Regular(top));
gen->stack.stack[gen->stack.sp] = Cudd_Not(next); gen->stack.sp++;
} else if (Cudd_Regular(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 = Cudd_Regular(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(Cudd_Regular(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 = Cudd_Regular(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(Cudd_Regular(top))) {
/* Take the else branch first. */
gen->gen.cubes.cube[Cudd_Regular(top)->index] = 0;
next = cuddE(Cudd_Regular(top));
gen->stack.stack[gen->stack.sp] = Cudd_Not(next); gen->stack.sp++;
} else if (Cudd_Regular(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 = Cudd_Regular(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(Cudd_Regular(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 [Finds the variables on which a ZDD depends.]
Description [Finds the variables on which a ZDD depends.
Returns a BDD consisting of the product of the variables if
successful; NULL otherwise.]
SideEffects [None]
SeeAlso [Cudd_Support]
******************************************************************************/
DdNode *
Cudd_zddSupport(
DdManager * dd /* manager */,
DdNode * f /* ZDD 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. */
zddSupportStep(Cudd_Regular(f),support);
zddClearFlag(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) {
/* The following call to cuddUniqueInter is guaranteed
** not to trigger reordering because the node we look up
** already exists. */
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_zddSupport */
/**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:
Static procedures included in this module:
]
SeeAlso []
Author [Fabio Somenzi]
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#include "util.h"
#include "cuddInt.h"
#ifndef PBORI_FORCE_ORIGINAL_CUDD
#include
Static procedures included in this module:
]
SeeAlso []
Author [Fabio Somenzi]
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#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.16 2012/02/05 01:07:19 fabio 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)(ptruint)(key) * DD_P1) >> (shift))
#else
#define lqHash(key,shift) \
(((unsigned)(key) * DD_P1) >> (shift))
#endif
/**AutomaticStart*************************************************************/
/*---------------------------------------------------------------------------*/
/* Static function prototypes */
/*---------------------------------------------------------------------------*/
static DdQueueItem * hashLookup(DdLevelQueue *queue, void *key);
static int hashInsert(DdLevelQueue *queue, DdQueueItem *item);
static void hashDelete(DdLevelQueue *queue, DdQueueItem *item);
static int hashResize(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);
/* Keep pointers to the insertion points for all levels. */
queue->last = ALLOC(DdQueueItem *, levels);
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;
queue->buckets = ALLOC(DdQueueItem *, queue->numBuckets);
if (queue->buckets == NULL) {
FREE(queue->last);
FREE(queue);
return(NULL);
}
memset(queue->last, 0, levels * sizeof(DdQueueItem *));
memset(queue->buckets, 0, queue->numBuckets * sizeof(DdQueueItem *));
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 */)
{
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. */
int 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 [Inserts the first key in a level queue.]
Description [Inserts the first key in a level queue. Returns a
pointer to the queue item if successful; NULL otherwise.]
SideEffects [None]
SeeAlso [cuddLevelQueueEnqueue]
******************************************************************************/
void *
cuddLevelQueueFirst(
DdLevelQueue * queue /* level queue */,
void * key /* key to be enqueued */,
int level /* level at which to insert */)
{
DdQueueItem *item;
#ifdef DD_DEBUG
assert(level < queue->levels);
/* Check whether entry for this node exists. */
item = hashLookup(queue,key);
assert(item == NULL);
#endif
/* 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 = 1;
/* No element precedes this one in the queue. */
queue->first = 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 cuddLevelQueueFirst */
/**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;
DdQueueItem **buckets;
DdQueueItem **oldBuckets = queue->buckets;
int shift;
int oldNumBuckets = queue->numBuckets;
extern DD_OOMFP MMoutOfMemory;
DD_OOMFP saveHandler;
/* Compute the new size of the subtable. */
numBuckets = oldNumBuckets << 1;
saveHandler = MMoutOfMemory;
MMoutOfMemory = Cudd_OutOfMem;
buckets = queue->buckets = ALLOC(DdQueueItem *, numBuckets);
MMoutOfMemory = saveHandler;
if (buckets == NULL) {
queue->maxsize <<= 1;
return(1);
}
queue->numBuckets = numBuckets;
shift = --(queue->shift);
queue->maxsize <<= 1;
memset(buckets, 0, numBuckets * sizeof(DdQueueItem *));
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 */
BRiAl-1.2.0/cudd/cuddLinear.c 0000664 0000000 0000000 00000114403 13173454145 0015612 0 ustar 00root root 0000000 0000000 /**CFile***********************************************************************
FileName [cuddLinear.c]
PackageName [cudd]
Synopsis [Functions for DD reduction by linear transformations.]
Description [ Internal procedures included in this module:
Static procedures included in this module:
]
Author [Fabio Somenzi]
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#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.29 2012/02/05 01:07:19 fabio 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 (int *ptrX, int *ptrY);
static int ddLinearAndSiftingAux (DdManager *table, int x, int xLow, int xHigh);
static Move * ddLinearAndSiftingUp (DdManager *table, int y, int xLow, Move *prevMoves);
static Move * ddLinearAndSiftingDown (DdManager *table, int x, int xHigh, Move *prevMoves);
static int ddLinearAndSiftingBackward (DdManager *table, int size, Move *moves);
static Move* ddUndoMoves (DdManager *table, Move *moves);
static void cuddXorLinear (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.
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),(DD_QSFP)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 */
/**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 <
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]
******************************************************************************/
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);
#ifdef 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;
#ifdef DD_DEBUG
last = NULL;
#endif
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 */
#ifdef DD_DEBUG
/* last is always assigned in the for loop because there is at
** least one key */
assert(last != NULL);
#endif
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 */
#ifdef 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 []
******************************************************************************/
void
cuddUpdateInteractionMatrix(
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 cuddUpdateInteractionMatrix */
/**Function********************************************************************
Synopsis [Initializes the linear transform matrix.]
Description [Initializes the linear transform matrix. Returns 1 if
successful; 0 otherwise.]
SideEffects [none]
SeeAlso []
******************************************************************************/
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 [Resizes the linear transform matrix. Returns 1 if
successful; 0 otherwise.]
SideEffects [none]
SeeAlso []
******************************************************************************/
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 */
/*---------------------------------------------------------------------------*/
/* 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;
cuddDeallocMove(table, moveDown);
moveDown = move;
}
while (moveUp != NULL) {
move = moveUp->next;
cuddDeallocMove(table, moveUp);
moveUp = move;
}
return(1);
ddLinearAndSiftingAuxOutOfMem:
while (moveDown != NULL) {
move = moveDown->next;
cuddDeallocMove(table, moveDown);
moveDown = move;
}
while (moveUp != NULL) {
move = moveUp->next;
cuddDeallocMove(table, 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;
cuddUpdateInteractionMatrix(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;
cuddDeallocMove(table, 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;
cuddUpdateInteractionMatrix(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;
cuddDeallocMove(table, 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;
cuddDeallocMove(table, invmoves);
invmoves = move;
}
return((Move *) CUDD_OUT_OF_MEM);
} /* end of ddUndoMoves */
/**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 */
BRiAl-1.2.0/cudd/cuddLiteral.c 0000664 0000000 0000000 00000020742 13173454145 0015776 0 ustar 00root root 0000000 0000000 /**CFile***********************************************************************
FileName [cuddLiteral.c]
PackageName [cudd]
Synopsis [Functions for manipulation of literal sets represented by
BDDs.]
Description [External procedures included in this file:
Internal procedures included in this file:
]
Author [Fabio Somenzi]
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#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.9 2012/02/05 01:07:19 fabio 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 */
/*---------------------------------------------------------------------------*/
BRiAl-1.2.0/cudd/cuddMatMult.c 0000664 0000000 0000000 00000050003 13173454145 0015756 0 ustar 00root root 0000000 0000000 /**CFile***********************************************************************
FileName [cuddMatMult.c]
PackageName [cudd]
Synopsis [Matrix multiplication functions.]
Description [External procedures included in this module:
Static procedures included in this module:
]
Author [Fabio Somenzi]
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#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.18 2012/02/05 01:07:19 fabio Exp $";
#endif
/*---------------------------------------------------------------------------*/
/* Macro declarations */
/*---------------------------------------------------------------------------*/
/**AutomaticStart*************************************************************/
/*---------------------------------------------------------------------------*/
/* Static function prototypes */
/*---------------------------------------------------------------------------*/
static DdNode * addMMRecur (DdManager *dd, DdNode *A, DdNode *B, int topP, int *vars);
static DdNode * addTriangleRecur (DdManager *dd, DdNode *f, DdNode *g, int *vars, DdNode *cube);
static DdNode * cuddAddOuterSumRecur (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;
DD_CTFP cacheOp;
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 = (DD_CTFP) 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 */
BRiAl-1.2.0/cudd/cuddPriority.c 0000664 0000000 0000000 00000163025 13173454145 0016225 0 ustar 00root root 0000000 0000000 /**CFile***********************************************************************
FileName [cuddPriority.c]
PackageName [cudd]
Synopsis [Priority functions.]
Description [External procedures included in this file:
Internal procedures included in this module:
Static procedures included in this module:
]
SeeAlso []
Author [Fabio Somenzi]
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#include "util.h"
#include "cuddInt.h"
/*---------------------------------------------------------------------------*/
/* Constant declarations */
/*---------------------------------------------------------------------------*/
#define DD_DEBUG 1
/*---------------------------------------------------------------------------*/
/* Stucture declarations */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Type declarations */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Variable declarations */
/*---------------------------------------------------------------------------*/
#ifndef lint
static char rcsid[] DD_UNUSED = "$Id: cuddPriority.c,v 1.36 2012/02/05 01:07:19 fabio Exp $";
#endif
/*---------------------------------------------------------------------------*/
/* Macro declarations */
/*---------------------------------------------------------------------------*/
/**AutomaticStart*************************************************************/
/*---------------------------------------------------------------------------*/
/* Static function prototypes */
/*---------------------------------------------------------------------------*/
static int cuddMinHammingDistRecur (DdNode * f, int *minterm, DdHashTable * table, int upperBound);
static DdNode * separateCube (DdManager *dd, DdNode *f, CUDD_VALUE_TYPE *distance);
static DdNode * createResult (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 vector
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:
]
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 */,
DD_PRFP Pifunc /* 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 > 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\].
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 (u == 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) > d(x,z).]
Description [This function generates a BDD for the function d(x,y)
> 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) > d(y,z).]
Description [This function generates a BDD for the function d(x,y)
> 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 [Generates a BDD for the function x - y ≥ c.]
Description [This function generates a BDD for the function x -y ≥ c.
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 a linear number of 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_Xgty]
******************************************************************************/
DdNode *
Cudd_Inequality(
DdManager * dd /* DD manager */,
int N /* number of x and y variables */,
int c /* right-hand side constant */,
DdNode ** x /* array of x variables */,
DdNode ** y /* array of y variables */)
{
/* The nodes at level i represent values of the difference that are
** multiples of 2^i. We use variables with names starting with k
** to denote the multipliers of 2^i in such multiples. */
int kTrue = c;
int kFalse = c - 1;
/* Mask used to compute the ceiling function. Since we divide by 2^i,
** we want to know whether the dividend is a multiple of 2^i. If it is,
** then ceiling and floor coincide; otherwise, they differ by one. */
int mask = 1;
int i;
DdNode *f = NULL; /* the eventual result */
DdNode *one = DD_ONE(dd);
DdNode *zero = Cudd_Not(one);
/* Two x-labeled nodes are created at most at each iteration. They are
** stored, along with their k values, in these variables. At each level,
** the old nodes are freed and the new nodes are copied into the old map.
*/
DdNode *map[2];
int invalidIndex = 1 << (N-1);
int index[2] = {invalidIndex, invalidIndex};
/* This should never happen. */
if (N < 0) return(NULL);
/* If there are no bits, both operands are 0. The result depends on c. */
if (N == 0) {
if (c >= 0) return(one);
else return(zero);
}
/* The maximum or the minimum difference comparing to c can generate the terminal case */
if ((1 << N) - 1 < c) return(zero);
else if ((-(1 << N) + 1) >= c) return(one);
/* Build the result bottom up. */
for (i = 1; i <= N; i++) {
int kTrueLower, kFalseLower;
int leftChild, middleChild, rightChild;
DdNode *g0, *g1, *fplus, *fequal, *fminus;
int j;
DdNode *newMap[2];
int newIndex[2];
kTrueLower = kTrue;
kFalseLower = kFalse;
/* kTrue = ceiling((c-1)/2^i) + 1 */
kTrue = ((c-1) >> i) + ((c & mask) != 1) + 1;
mask = (mask << 1) | 1;
/* kFalse = floor(c/2^i) - 1 */
kFalse = (c >> i) - 1;
newIndex[0] = invalidIndex;
newIndex[1] = invalidIndex;
for (j = kFalse + 1; j < kTrue; j++) {
/* Skip if node is not reachable from top of BDD. */
if ((j >= (1 << (N - i))) || (j <= -(1 << (N -i)))) continue;
/* Find f- */
leftChild = (j << 1) - 1;
if (leftChild >= kTrueLower) {
fminus = one;
} else if (leftChild <= kFalseLower) {
fminus = zero;
} else {
assert(leftChild == index[0] || leftChild == index[1]);
if (leftChild == index[0]) {
fminus = map[0];
} else {
fminus = map[1];
}
}
/* Find f= */
middleChild = j << 1;
if (middleChild >= kTrueLower) {
fequal = one;
} else if (middleChild <= kFalseLower) {
fequal = zero;
} else {
assert(middleChild == index[0] || middleChild == index[1]);
if (middleChild == index[0]) {
fequal = map[0];
} else {
fequal = map[1];
}
}
/* Find f+ */
rightChild = (j << 1) + 1;
if (rightChild >= kTrueLower) {
fplus = one;
} else if (rightChild <= kFalseLower) {
fplus = zero;
} else {
assert(rightChild == index[0] || rightChild == index[1]);
if (rightChild == index[0]) {
fplus = map[0];
} else {
fplus = map[1];
}
}
/* Build new nodes. */
g1 = Cudd_bddIte(dd, y[N - i], fequal, fplus);
if (g1 == NULL) {
if (index[0] != invalidIndex) Cudd_IterDerefBdd(dd, map[0]);
if (index[1] != invalidIndex) Cudd_IterDerefBdd(dd, map[1]);
if (newIndex[0] != invalidIndex) Cudd_IterDerefBdd(dd, newMap[0]);
if (newIndex[1] != invalidIndex) Cudd_IterDerefBdd(dd, newMap[1]);
return(NULL);
}
cuddRef(g1);
g0 = Cudd_bddIte(dd, y[N - i], fminus, fequal);
if (g0 == NULL) {
Cudd_IterDerefBdd(dd, g1);
if (index[0] != invalidIndex) Cudd_IterDerefBdd(dd, map[0]);
if (index[1] != invalidIndex) Cudd_IterDerefBdd(dd, map[1]);
if (newIndex[0] != invalidIndex) Cudd_IterDerefBdd(dd, newMap[0]);
if (newIndex[1] != invalidIndex) Cudd_IterDerefBdd(dd, newMap[1]);
return(NULL);
}
cuddRef(g0);
f = Cudd_bddIte(dd, x[N - i], g1, g0);
if (f == NULL) {
Cudd_IterDerefBdd(dd, g1);
Cudd_IterDerefBdd(dd, g0);
if (index[0] != invalidIndex) Cudd_IterDerefBdd(dd, map[0]);
if (index[1] != invalidIndex) Cudd_IterDerefBdd(dd, map[1]);
if (newIndex[0] != invalidIndex) Cudd_IterDerefBdd(dd, newMap[0]);
if (newIndex[1] != invalidIndex) Cudd_IterDerefBdd(dd, newMap[1]);
return(NULL);
}
cuddRef(f);
Cudd_IterDerefBdd(dd, g1);
Cudd_IterDerefBdd(dd, g0);
/* Save newly computed node in map. */
assert(newIndex[0] == invalidIndex || newIndex[1] == invalidIndex);
if (newIndex[0] == invalidIndex) {
newIndex[0] = j;
newMap[0] = f;
} else {
newIndex[1] = j;
newMap[1] = f;
}
}
/* Copy new map to map. */
if (index[0] != invalidIndex) Cudd_IterDerefBdd(dd, map[0]);
if (index[1] != invalidIndex) Cudd_IterDerefBdd(dd, map[1]);
map[0] = newMap[0];
map[1] = newMap[1];
index[0] = newIndex[0];
index[1] = newIndex[1];
}
cuddDeref(f);
return(f);
} /* end of Cudd_Inequality */
/**Function********************************************************************
Synopsis [Generates a BDD for the function x - y != c.]
Description [This function generates a BDD for the function x -y != c.
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 a linear number of 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_Xgty]
******************************************************************************/
DdNode *
Cudd_Disequality(
DdManager * dd /* DD manager */,
int N /* number of x and y variables */,
int c /* right-hand side constant */,
DdNode ** x /* array of x variables */,
DdNode ** y /* array of y variables */)
{
/* The nodes at level i represent values of the difference that are
** multiples of 2^i. We use variables with names starting with k
** to denote the multipliers of 2^i in such multiples. */
int kTrueLb = c + 1;
int kTrueUb = c - 1;
int kFalse = c;
/* Mask used to compute the ceiling function. Since we divide by 2^i,
** we want to know whether the dividend is a multiple of 2^i. If it is,
** then ceiling and floor coincide; otherwise, they differ by one. */
int mask = 1;
int i;
DdNode *f = NULL; /* the eventual result */
DdNode *one = DD_ONE(dd);
DdNode *zero = Cudd_Not(one);
/* Two x-labeled nodes are created at most at each iteration. They are
** stored, along with their k values, in these variables. At each level,
** the old nodes are freed and the new nodes are copied into the old map.
*/
DdNode *map[2];
int invalidIndex = 1 << (N-1);
int index[2] = {invalidIndex, invalidIndex};
/* This should never happen. */
if (N < 0) return(NULL);
/* If there are no bits, both operands are 0. The result depends on c. */
if (N == 0) {
if (c != 0) return(one);
else return(zero);
}
/* The maximum or the minimum difference comparing to c can generate the terminal case */
if ((1 << N) - 1 < c || (-(1 << N) + 1) > c) return(one);
/* Build the result bottom up. */
for (i = 1; i <= N; i++) {
int kTrueLbLower, kTrueUbLower;
int leftChild, middleChild, rightChild;
DdNode *g0, *g1, *fplus, *fequal, *fminus;
int j;
DdNode *newMap[2];
int newIndex[2];
kTrueLbLower = kTrueLb;
kTrueUbLower = kTrueUb;
/* kTrueLb = floor((c-1)/2^i) + 2 */
kTrueLb = ((c-1) >> i) + 2;
/* kTrueUb = ceiling((c+1)/2^i) - 2 */
kTrueUb = ((c+1) >> i) + (((c+2) & mask) != 1) - 2;
mask = (mask << 1) | 1;
newIndex[0] = invalidIndex;
newIndex[1] = invalidIndex;
for (j = kTrueUb + 1; j < kTrueLb; j++) {
/* Skip if node is not reachable from top of BDD. */
if ((j >= (1 << (N - i))) || (j <= -(1 << (N -i)))) continue;
/* Find f- */
leftChild = (j << 1) - 1;
if (leftChild >= kTrueLbLower || leftChild <= kTrueUbLower) {
fminus = one;
} else if (i == 1 && leftChild == kFalse) {
fminus = zero;
} else {
assert(leftChild == index[0] || leftChild == index[1]);
if (leftChild == index[0]) {
fminus = map[0];
} else {
fminus = map[1];
}
}
/* Find f= */
middleChild = j << 1;
if (middleChild >= kTrueLbLower || middleChild <= kTrueUbLower) {
fequal = one;
} else if (i == 1 && middleChild == kFalse) {
fequal = zero;
} else {
assert(middleChild == index[0] || middleChild == index[1]);
if (middleChild == index[0]) {
fequal = map[0];
} else {
fequal = map[1];
}
}
/* Find f+ */
rightChild = (j << 1) + 1;
if (rightChild >= kTrueLbLower || rightChild <= kTrueUbLower) {
fplus = one;
} else if (i == 1 && rightChild == kFalse) {
fplus = zero;
} else {
assert(rightChild == index[0] || rightChild == index[1]);
if (rightChild == index[0]) {
fplus = map[0];
} else {
fplus = map[1];
}
}
/* Build new nodes. */
g1 = Cudd_bddIte(dd, y[N - i], fequal, fplus);
if (g1 == NULL) {
if (index[0] != invalidIndex) Cudd_IterDerefBdd(dd, map[0]);
if (index[1] != invalidIndex) Cudd_IterDerefBdd(dd, map[1]);
if (newIndex[0] != invalidIndex) Cudd_IterDerefBdd(dd, newMap[0]);
if (newIndex[1] != invalidIndex) Cudd_IterDerefBdd(dd, newMap[1]);
return(NULL);
}
cuddRef(g1);
g0 = Cudd_bddIte(dd, y[N - i], fminus, fequal);
if (g0 == NULL) {
Cudd_IterDerefBdd(dd, g1);
if (index[0] != invalidIndex) Cudd_IterDerefBdd(dd, map[0]);
if (index[1] != invalidIndex) Cudd_IterDerefBdd(dd, map[1]);
if (newIndex[0] != invalidIndex) Cudd_IterDerefBdd(dd, newMap[0]);
if (newIndex[1] != invalidIndex) Cudd_IterDerefBdd(dd, newMap[1]);
return(NULL);
}
cuddRef(g0);
f = Cudd_bddIte(dd, x[N - i], g1, g0);
if (f == NULL) {
Cudd_IterDerefBdd(dd, g1);
Cudd_IterDerefBdd(dd, g0);
if (index[0] != invalidIndex) Cudd_IterDerefBdd(dd, map[0]);
if (index[1] != invalidIndex) Cudd_IterDerefBdd(dd, map[1]);
if (newIndex[0] != invalidIndex) Cudd_IterDerefBdd(dd, newMap[0]);
if (newIndex[1] != invalidIndex) Cudd_IterDerefBdd(dd, newMap[1]);
return(NULL);
}
cuddRef(f);
Cudd_IterDerefBdd(dd, g1);
Cudd_IterDerefBdd(dd, g0);
/* Save newly computed node in map. */
assert(newIndex[0] == invalidIndex || newIndex[1] == invalidIndex);
if (newIndex[0] == invalidIndex) {
newIndex[0] = j;
newMap[0] = f;
} else {
newIndex[1] = j;
newMap[1] = f;
}
}
/* Copy new map to map. */
if (index[0] != invalidIndex) Cudd_IterDerefBdd(dd, map[0]);
if (index[1] != invalidIndex) Cudd_IterDerefBdd(dd, map[1]);
map[0] = newMap[0];
map[1] = newMap[1];
index[0] = newIndex[0];
index[1] = newIndex[1];
}
cuddDeref(f);
return(f);
} /* end of Cudd_Disequality */
/**Function********************************************************************
Synopsis [Generates a BDD for the function lowerB ≤ x ≤ upperB.]
Description [This function generates a BDD for the function
lowerB ≤ x ≤ upperB, where x is an N-bit number,
x\[0\] x\[1\] ... x\[N-1\], with 0 the most significant bit (important!).
The number of variables N should be sufficient to represent the bounds;
otherwise, the bounds are truncated to their N least significant bits.
Two BDDs are built bottom-up for lowerB ≤ x and x ≤ upperB, and they
are finally conjoined.]
SideEffects [None]
SeeAlso [Cudd_Xgty]
******************************************************************************/
DdNode *
Cudd_bddInterval(
DdManager * dd /* DD manager */,
int N /* number of x variables */,
DdNode ** x /* array of x variables */,
unsigned int lowerB /* lower bound */,
unsigned int upperB /* upper bound */)
{
DdNode *one, *zero;
DdNode *r, *rl, *ru;
int i;
one = DD_ONE(dd);
zero = Cudd_Not(one);
rl = one;
cuddRef(rl);
ru = one;
cuddRef(ru);
/* Loop to build the rest of the BDDs. */
for (i = N-1; i >= 0; i--) {
DdNode *vl, *vu;
vl = Cudd_bddIte(dd, x[i],
lowerB&1 ? rl : one,
lowerB&1 ? zero : rl);
if (vl == NULL) {
Cudd_IterDerefBdd(dd, rl);
Cudd_IterDerefBdd(dd, ru);
return(NULL);
}
cuddRef(vl);
Cudd_IterDerefBdd(dd, rl);
rl = vl;
lowerB >>= 1;
vu = Cudd_bddIte(dd, x[i],
upperB&1 ? ru : zero,
upperB&1 ? one : ru);
if (vu == NULL) {
Cudd_IterDerefBdd(dd, rl);
Cudd_IterDerefBdd(dd, ru);
return(NULL);
}
cuddRef(vu);
Cudd_IterDerefBdd(dd, ru);
ru = vu;
upperB >>= 1;
}
/* Conjoin the two bounds. */
r = Cudd_bddAnd(dd, rl, ru);
if (r == NULL) {
Cudd_IterDerefBdd(dd, rl);
Cudd_IterDerefBdd(dd, ru);
return(NULL);
}
cuddRef(r);
Cudd_IterDerefBdd(dd, rl);
Cudd_IterDerefBdd(dd, ru);
cuddDeref(r);
return(r);
} /* end of Cudd_bddInterval */
/**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 (Cudd_CheckCube(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
according to the following formula.
H(f,g) = min(H(ft,gt), H(fe,ge), H(ft,ge)+1, H(fe,gt)+1)
Bounding is based on the following observations.
The variable bound
is set at the largest value of the distance
that we are still interested in. Therefore, we desist when
(bound == -1) and (F != not(G)) or (bound == 0) and (F == not(G)).
If we were maximally aggressive in using the bound, we would always
set the bound to the minimum distance seen thus far minus one. That
is, we would maintain the invariant
bound < minD,
except at the very beginning, when we have no value for
minD
.bound < minD
when examining the
two negative cofactors, because we try to find a large cube at
minimum distance. To do so, we try to find a cube in the negative
cofactors at the same or smaller distance from the cube found in the
positive cofactors.H(ft,ge)
and H(fe,gt)
we
know that we are going to add 1 to the result of the recursive call
to account for the difference in the splitting variable. Therefore,
we decrease the bound correspondingly.f
and
g
depend on the top variable.gt == ge == g
. (That is, g
does
not depend on the top variable.) Then
H(f,g) = min(H(ft,g), H(fe,g), H(ft,g)+1, H(fe,g)+1)
= min(H(ft,g), H(fe,g)) .
Therefore, under these circumstances, we skip the two "cross" cases.
]
SeeAlso [cudd_addHarwell.c]
Author [Fabio Somenzi]
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#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.7 2012/02/05 01:07:19 fabio 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.
Internal procedures included in this module:
]
SeeAlso []
Author [Fabio Somenzi]
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#include "util.h"
#include "cuddInt.h"
#ifndef PBORI_FORCE_ORIGINAL_CUDD
#include
Internal procedures included in this module:
Static procedures included in this module:
]
Author [Shipra Panda, Bernard Plessier, Fabio Somenzi]
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#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.71 2012/02/05 01:07:19 fabio Exp $";
#endif
static int *entry;
int ddTotalNumberSwapping;
#ifdef DD_STATS
int ddTotalNISwaps;
#endif
/*---------------------------------------------------------------------------*/
/* Macro declarations */
/*---------------------------------------------------------------------------*/
/**AutomaticStart*************************************************************/
/*---------------------------------------------------------------------------*/
/* Static function prototypes */
/*---------------------------------------------------------------------------*/
static int ddUniqueCompare (int *ptrX, int *ptrY);
static Move * ddSwapAny (DdManager *table, int x, int y);
static int ddSiftingAux (DdManager *table, int x, int xLow, int xHigh);
static Move * ddSiftingUp (DdManager *table, int y, int xLow);
static Move * ddSiftingDown (DdManager *table, int x, int xHigh);
static int ddSiftingBackward (DdManager *table, int size, Move *moves);
static int ddReorderPreprocess (DdManager *table);
static int ddReorderPostprocess (DdManager *table);
static int ddShuffle (DdManager *table, int *permutation);
static int ddSiftUp (DdManager *table, int x, int xLow);
static void bddFixTree (DdManager *table, MtrNode *treenode);
static int ddUpdateMtrTree (DdManager *table, MtrNode *treenode, int *perm, int *invperm);
static int ddCheckPermuation (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:
For sifting, symmetric sifting, group sifting, and window
permutation it is possible to request reordering to convergence.
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),(DD_QSFP)ddUniqueCompare);
/* Now sift. */
for (i = 0; i < ddMin(table->siftMaxVar,size); i++) {
if (ddTotalNumberSwapping >= table->siftMaxSwap)
break;
if (util_cpu_time() - table->startTime + table->reordTime
> table->timeLimit) {
table->autoDyn = 0; /* prevent further reordering */
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.
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;
cuddDeallocMove(table, 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;
cuddDeallocMove(table, 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 < 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 DD_OOMFP MMoutOfMemory;
DD_OOMFP saveHandler;
#ifdef 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. */
newxshift = xshift;
newxslots = xslots;
while ((unsigned) oldxkeys > DD_MAX_SUBTABLE_DENSITY * newxslots) {
newxshift--;
newxslots <<= 1;
}
while ((unsigned) oldxkeys < newxslots &&
newxslots > table->initSlots) {
newxshift++;
newxslots >>= 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 += ((int) 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 +=
((int) 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 */
#ifdef 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
M
be the ratio of the two numbers. cuddBddAlignToZdd
then considers the ZDD variables from M*i
to
(M+1)*i-1
as corresponding to BDD variable
i
. 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;
cuddDeallocMove(table, 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;
cuddDeallocMove(table, moveDown);
moveDown = move;
}
while (moveUp != NULL) {
move = moveUp->next;
cuddDeallocMove(table, moveUp);
moveUp = move;
}
return(1);
ddSiftingAuxOutOfMem:
if (moveDown != (Move *) CUDD_OUT_OF_MEM) {
while (moveDown != NULL) {
move = moveDown->next;
cuddDeallocMove(table, moveDown);
moveDown = move;
}
}
if (moveUp != (Move *) CUDD_OUT_OF_MEM) {
while (moveUp != NULL) {
move = moveUp->next;
cuddDeallocMove(table, 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;
cuddDeallocMove(table, 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;
cuddDeallocMove(table, 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
unsigned 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)
{
unsigned int i, size;
int index, level, minLevel, maxLevel, minIndex;
if (treenode == NULL) return(1);
minLevel = CUDD_MAXINDEX;
maxLevel = 0;
minIndex = -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 (minIndex == -1) return(0);
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)
{
unsigned int i, size;
int index, level, 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);
}
BRiAl-1.2.0/cudd/cuddSat.c 0000664 0000000 0000000 00000141417 13173454145 0015134 0 ustar 00root root 0000000 0000000 /**CFile***********************************************************************
FileName [cuddSat.c]
PackageName [cudd]
Synopsis [Functions for the solution of satisfiability related problems.]
Description [External procedures included in this file:
Internal procedures included in this module:
Static procedures included in this module:
]
Author [Seh-Woong Jeong, Fabio Somenzi]
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#include "util.h"
#include "cuddInt.h"
/*---------------------------------------------------------------------------*/
/* Constant declarations */
/*---------------------------------------------------------------------------*/
#define DD_BIGGY 100000000
/*---------------------------------------------------------------------------*/
/* 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.39 2012/02/05 01:07:19 fabio Exp $";
#endif
static DdNode *one, *zero;
/*---------------------------------------------------------------------------*/
/* Macro declarations */
/*---------------------------------------------------------------------------*/
#define WEIGHT(weight, col) ((weight) == NULL ? 1 : weight[col])
#ifdef __cplusplus
extern "C" {
#endif
/**AutomaticStart*************************************************************/
/*---------------------------------------------------------------------------*/
/* Static function prototypes */
/*---------------------------------------------------------------------------*/
static enum st_retval freePathPair (char *key, char *value, char *arg);
static cuddPathPair getShortest (DdNode *root, int *cost, int *support, st_table *visited);
static DdNode * getPath (DdManager *manager, st_table *visited, DdNode *f, int *weight, int cost);
static cuddPathPair getLargest (DdNode *root, st_table *visited);
static DdNode * getCube (DdManager *manager, st_table *visited, DdNode *f, int cost);
static DdNode * ddBddMaximallyExpand(DdManager *dd, DdNode *lb, DdNode *ub, DdNode *f);
static int ddBddShortestPathUnate(DdManager *dd, DdNode *f, int *phases, st_table *table);
static DdNode * ddGetLargestCubeUnate(DdManager *dd, DdNode *f, int *phases, st_table *table);
/**AutomaticEnd***************************************************************/
#ifdef __cplusplus
}
#endif
/*---------------------------------------------------------------------------*/
/* 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)
{
DdNode *F;
st_table *visited;
DdNode *sol;
cuddPathPair *rootPair;
int complement, cost;
int i;
one = DD_ONE(manager);
zero = DD_ZERO(manager);
/* Initialize support. Support does not depend on variable order.
** Hence, it does not need to be reinitialized if reordering occurs.
*/
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. */
do {
manager->reordered = 0;
/* 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);
if (!st_lookup(visited, F, &rootPair)) return(NULL);
if (complement) {
cost = rootPair->neg;
} else {
cost = rootPair->pos;
}
/* Recover an actual shortest path. */
sol = getPath(manager,visited,f,weight,cost);
st_foreach(visited, freePathPair, NULL);
st_free_table(visited);
} while (manager->reordered == 1);
*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 the location
pointed by length if it is non-null.]
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) {
if (length != NULL) {
*length = DD_BIGGY;
}
return(Cudd_Not(one));
}
/* From this point on, a path exists. */
do {
manager->reordered = 0;
/* 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);
if (!st_lookup(visited, F, &rootPair)) return(NULL);
if (complement) {
cost = rootPair->neg;
} else {
cost = rootPair->pos;
}
/* Recover an actual shortest path. */
sol = getCube(manager,visited,f,cost);
st_foreach(visited, freePathPair, NULL);
st_free_table(visited);
} while (manager->reordered == 1);
if (length != NULL) {
*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 such a path is found; a large number if the function is
identically 0, and CUDD_OUT_OF_MEM in case of failure.]
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);
if (!st_lookup(visited, F, &my_pair)) return(CUDD_OUT_OF_MEM);
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;
DD_CTFP cacheOp;
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 = (DD_CTFP) 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 increasing) 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 pr
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");
(void) fprintf(dd->out,
"f: address = %p\t value = %40.30f\n",
(void *) f, cuddV(f));
(void) fprintf(dd->out,
"g: address = %p\t value = %40.30f\n",
(void *) g, cuddV(g));
}
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,(DD_CTFP)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,(DD_CTFP)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 [Cudd_bddMaximallyExpand]
******************************************************************************/
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 */
/**Function********************************************************************
Synopsis [Expands lb to prime implicants of (f and ub).]
Description [Expands lb to all prime implicants of (f and ub) that contain lb.
Assumes that lb is contained in ub. Returns the disjunction of the primes if
lb is contained in f; returns the zero BDD if lb is not contained in f;
returns NULL in case of failure. In particular, NULL is returned if cube is
not a real cube or is not an implicant of f. Returning the disjunction of
all prime implicants works because the resulting function is unate.]
SideEffects [None]
SeeAlso [Cudd_bddMakePrime]
******************************************************************************/
DdNode *
Cudd_bddMaximallyExpand(
DdManager *dd /* manager */,
DdNode *lb /* cube to be expanded */,
DdNode *ub /* upper bound cube */,
DdNode *f /* function against which to expand */)
{
DdNode *res;
if (!Cudd_bddLeq(dd,lb,ub)) return(NULL);
do {
dd->reordered = 0;
res = ddBddMaximallyExpand(dd,lb,ub,f);
} while (dd->reordered == 1);
return(res);
} /* end of Cudd_bddMaximallyExpand */
/**Function********************************************************************
Synopsis [Find a largest prime of a unate function.]
Description [Find a largest prime implicant of a unate function.
Returns the BDD for the prime if succesful; NULL otherwise. The behavior
is undefined if f is not unate. The third argument is used to determine
whether f is unate positive (increasing) or negative (decreasing)
in each of the variables in its support.]
SideEffects [None]
SeeAlso [Cudd_bddMaximallyExpand]
******************************************************************************/
DdNode *
Cudd_bddLargestPrimeUnate(
DdManager *dd /* manager */,
DdNode *f /* unate function */,
DdNode *phaseBdd /* cube of the phases */)
{
DdNode *res;
int *phases;
int retval;
st_table *table;
/* Extract phase vector for quick access. */
phases = ALLOC(int, dd->size);
if (phases == NULL) return(NULL);
retval = Cudd_BddToCubeArray(dd, phaseBdd, phases);
if (retval == 0) {
FREE(phases);
return(NULL);
}
do {
dd->reordered = 0;
table = st_init_table(st_ptrcmp,st_ptrhash);
if (table == NULL) {
FREE(phases);
return(NULL);
}
(void) ddBddShortestPathUnate(dd, f, phases, table);
res = ddGetLargestCubeUnate(dd, f, phases, table);
st_free_table(table);
} while (dd->reordered == 1);
FREE(phases);
return(res);
} /* end of Cudd_bddLargestPrimeUnate */
/*---------------------------------------------------------------------------*/
/* 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) {
Cudd_RecursiveDeref(dd,res);
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, my_root, &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, Cudd_Regular(T), &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, Cudd_Regular(E), &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, my_root, &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) { /* simply 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;
/* Caching may fail without affecting correctness. */
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);}
if (!st_lookup(visited, Cudd_Regular(T), &T_pair)) return(NULL);
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;
}
if (!st_lookup(visited, Cudd_Regular(E), &E_pair)) return(NULL);
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 */
/**Function********************************************************************
Synopsis [Performs the recursive step of Cudd_bddMaximallyExpand.]
Description [Performs the recursive step of Cudd_bddMaximallyExpand.
Returns set of primes or zero BDD if successful; NULL otherwise. On entry
to this function, ub and lb should be different from the zero BDD. The
function then maintains this invariant.]
SideEffects [None]
SeeAlso []
******************************************************************************/
static DdNode *
ddBddMaximallyExpand(
DdManager *dd /* manager */,
DdNode *lb /* cube to be expanded */,
DdNode *ub /* upper bound cube */,
DdNode *f /* function against which to expand */)
{
DdNode *one, *zero, *lbv, *lbvn, *lbnx, *ubv, *ubvn, *fv, *fvn, *res;
DdNode *F, *UB, *LB, *t, *e;
unsigned int top, toplb, topub, topf, index;
statLine(dd);
/* Terminal cases. */
one = DD_ONE(dd);
zero = Cudd_Not(one);
assert(ub != zero && lb != zero);
/** There are three major terminal cases in theory:
** ub -> f : return ub
** lb == f : return lb
** not(lb -> f): return zero
** Only the second case can be checked exactly in constant time.
** For the others, we check for sufficient conditions.
*/
if (ub == f || f == one) return(ub);
if (lb == f) return(lb);
if (f == zero || ub == Cudd_Not(f) || lb == one || lb == Cudd_Not(f))
return(zero);
if (!Cudd_IsComplement(lb) && Cudd_IsComplement(f)) return(zero);
/* Here lb and f are not constant. */
/* Check cache. Since lb and ub are cubes, their local reference counts
** are always 1. Hence, we only check the reference count of f.
*/
F = Cudd_Regular(f);
if (F->ref != 1) {
DdNode *tmp = cuddCacheLookup(dd, DD_BDD_MAX_EXP_TAG, lb, ub, f);
if (tmp != NULL) {
return(tmp);
}
}
/* Compute cofactors. For lb we use the non-zero one in
** both branches of the recursion.
*/
LB = Cudd_Regular(lb);
UB = Cudd_Regular(ub);
topf = dd->perm[F->index];
toplb = dd->perm[LB->index];
topub = (ub == one) ? CUDD_CONST_INDEX : dd->perm[UB->index];
assert(toplb <= topub);
top = ddMin(topf,toplb);
if (toplb == top) {
index = LB->index;
lbv = cuddT(LB);
lbvn = cuddE(LB);
if (lb != LB) {
lbv = Cudd_Not(lbv);
lbvn = Cudd_Not(lbvn);
}
if (lbv == zero) {
lbnx = lbvn;
} else {
lbnx = lbv;
}
} else {
index = F->index;
lbnx = lbv = lbvn = lb;
}
if (topub == top) {
ubv = cuddT(UB);
ubvn = cuddE(UB);
if (ub != UB) {
ubv = Cudd_Not(ubv);
ubvn = Cudd_Not(ubvn);
}
} else {
ubv = ubvn = ub;
}
if (topf == top) {
fv = cuddT(F);
fvn = cuddE(F);
if (f != F) {
fv = Cudd_Not(fv);
fvn = Cudd_Not(fvn);
}
} else {
fv = fvn = f;
}
/* Recursive calls. */
if (ubv != zero) {
t = ddBddMaximallyExpand(dd, lbnx, ubv, fv);
if (t == NULL) return(NULL);
} else {
assert(topub == toplb && topub == top && lbv == zero);
t = zero;
}
cuddRef(t);
/* If the top variable appears only in lb, the positive and negative
** cofactors of each operand are the same. We want to avoid a
** needless recursive call, which would force us to give up the
** cache optimization trick based on reference counts.
*/
if (ubv == ubvn && fv == fvn) {
res = t;
} else {
if (ubvn != zero) {
e = ddBddMaximallyExpand(dd, lbnx, ubvn, fvn);
if (e == NULL) {
Cudd_IterDerefBdd(dd,t);
return(NULL);
}
} else {
assert(topub == toplb && topub == top && lbvn == zero);
e = zero;
}
if (t == e) {
res = t;
} else {
cuddRef(e);
if (toplb == top) {
if (lbv == zero) {
/* Top variable appears in negative phase. */
if (t != one) {
DdNode *newT;
if (Cudd_IsComplement(t)) {
newT = cuddUniqueInter(dd, index, Cudd_Not(t), zero);
if (newT == NULL) {
Cudd_IterDerefBdd(dd,t);
Cudd_IterDerefBdd(dd,e);
return(NULL);
}
newT = Cudd_Not(newT);
} else {
newT = cuddUniqueInter(dd, index, t, one);
if (newT == NULL) {
Cudd_IterDerefBdd(dd,t);
Cudd_IterDerefBdd(dd,e);
return(NULL);
}
}
cuddRef(newT);
cuddDeref(t);
t = newT;
}
} else if (lbvn == zero) {
/* Top variable appears in positive phase. */
if (e != one) {
DdNode *newE;
newE = cuddUniqueInter(dd, index, one, e);
if (newE == NULL) {
Cudd_IterDerefBdd(dd,t);
Cudd_IterDerefBdd(dd,e);
return(NULL);
}
cuddRef(newE);
cuddDeref(e);
e = newE;
}
} else {
/* Not a cube. */
Cudd_IterDerefBdd(dd,t);
Cudd_IterDerefBdd(dd,e);
return(NULL);
}
}
/* Combine results. */
res = cuddBddAndRecur(dd, 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);
}
}
/* Cache result and return. */
if (F->ref != 1) {
cuddCacheInsert(dd, DD_BDD_MAX_EXP_TAG, lb, ub, f, res);
}
cuddDeref(res);
return(res);
} /* end of ddBddMaximallyExpand */
/**Function********************************************************************
Synopsis [Performs shortest path computation on a unate function.]
Description [Performs shortest path computation on a unate function.
Returns the length of the shortest path to one if successful;
CUDD_OUT_OF_MEM otherwise. This function is based on the observation
that in the BDD of a unate function no node except the constant is
reachable from the root via paths of different parity.]
SideEffects [None]
SeeAlso [getShortest]
******************************************************************************/
static int
ddBddShortestPathUnate(
DdManager *dd,
DdNode *f,
int *phases,
st_table *table)
{
int positive, l, lT, lE;
DdNode *one = DD_ONE(dd);
DdNode *zero = Cudd_Not(one);
DdNode *F, *fv, *fvn;
if (st_lookup_int(table, f, &l)) {
return(l);
}
if (f == one) {
l = 0;
} else if (f == zero) {
l = DD_BIGGY;
} else {
F = Cudd_Regular(f);
fv = cuddT(F);
fvn = cuddE(F);
if (f != F) {
fv = Cudd_Not(fv);
fvn = Cudd_Not(fvn);
}
lT = ddBddShortestPathUnate(dd, fv, phases, table);
lE = ddBddShortestPathUnate(dd, fvn, phases, table);
positive = phases[F->index];
l = positive ? ddMin(lT+1, lE) : ddMin(lT, lE+1);
}
if (st_insert(table, f, (void *)(ptrint) l) == ST_OUT_OF_MEM) {
return(CUDD_OUT_OF_MEM);
}
return(l);
} /* end of ddShortestPathUnate */
/**Function********************************************************************
Synopsis [Extracts largest prime of a unate function.]
Description [Extracts largest prime of a unate function. Returns the BDD of
the prime if successful; NULL otherwise.]
SideEffects [None]
SeeAlso [getPath]
******************************************************************************/
static DdNode *
ddGetLargestCubeUnate(
DdManager *dd,
DdNode *f,
int *phases,
st_table *table)
{
DdNode *res, *scan;
DdNode *one = DD_ONE(dd);
int cost;
res = one;
cuddRef(res);
scan = f;
st_lookup_int(table, scan, &cost);
while (!Cudd_IsConstant(scan)) {
int Pcost, Ncost, Tcost;
DdNode *tmp, *T, *E;
DdNode *rscan = Cudd_Regular(scan);
int index = rscan->index;
assert(phases[index] == 0 || phases[index] == 1);
int positive = phases[index] == 1;
Pcost = positive ? cost - 1 : cost;
Ncost = positive ? cost : cost - 1;
T = cuddT(rscan);
E = cuddE(rscan);
if (rscan != scan) {
T = Cudd_Not(T);
E = Cudd_Not(E);
}
tmp = res;
st_lookup_int(table, T, &Tcost);
if (Tcost == Pcost) {
cost = Pcost;
scan = T;
if (positive) {
tmp = cuddBddAndRecur(dd, dd->vars[index], res);
}
} else {
cost = Ncost;
scan = E;
if (!positive) {
tmp = cuddBddAndRecur(dd, Cudd_Not(dd->vars[index]), res);
}
}
if (tmp == NULL) {
Cudd_IterDerefBdd(dd, res);
return(NULL);
}
cuddRef(tmp);
Cudd_IterDerefBdd(dd, res);
res = tmp;
}
cuddDeref(res);
return(res);
} /* end of ddGetLargestCubeUnate */
BRiAl-1.2.0/cudd/cuddSign.c 0000664 0000000 0000000 00000024471 13173454145 0015305 0 ustar 00root root 0000000 0000000 /**CFile***********************************************************************
FileName [cuddSign.c]
PackageName [cudd]
Synopsis [Computation of signatures.]
Description [External procedures included in this module:
Static procedures included in this module:
]
Author [Fabio Somenzi]
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#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.24 2012/02/05 01:07:19 fabio 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 (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 has 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
unsigned 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, node, &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 */
BRiAl-1.2.0/cudd/cuddSolve.c 0000664 0000000 0000000 00000025202 13173454145 0015466 0 ustar 00root root 0000000 0000000 /**CFile***********************************************************************
FileName [cuddSolve.c]
PackageName [cudd]
Synopsis [Boolean equation solver and related functions.]
Description [External functions included in this modoule:
Internal functions included in this module:
]
SeeAlso []
Author [Balakrishna Kumthekar]
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#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.13 2012/02/05 01:07:19 fabio 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 */
/*---------------------------------------------------------------------------*/
BRiAl-1.2.0/cudd/cuddSplit.c 0000664 0000000 0000000 00000046120 13173454145 0015473 0 ustar 00root root 0000000 0000000 /**CFile***********************************************************************
FileName [cuddSplit.c]
PackageName [cudd]
Synopsis [Returns a subset of minterms from a boolean function.]
Description [External functions included in this modoule:
Internal functions included in this module:
]
SeeAlso []
Author [Balakrishna Kumthekar]
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#include "util.h"
#include "cuddInt.h"
/*---------------------------------------------------------------------------*/
/* Constant declarations */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Type declarations */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Structure declarations */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Variable declarations */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Macro declarations */
/*---------------------------------------------------------------------------*/
/**AutomaticStart*************************************************************/
/*---------------------------------------------------------------------------*/
/* Static function prototypes */
/*---------------------------------------------------------------------------*/
static DdNode * selectMintermsFromUniverse (DdManager *manager, int *varSeen, double n);
static DdNode * mintermsFromUniverse (DdManager *manager, DdNode **vars, int numVars, double n, int index);
static double bddAnnotateMintermCount (DdManager *manager, DdNode *node, double max, st_table *table);
/**AutomaticEnd***************************************************************/
/*---------------------------------------------------------------------------*/
/* Definition of exported functions */
/*---------------------------------------------------------------------------*/
/**Function********************************************************************
Synopsis [Returns m minterms from a BDD.]
Description [Returns m
minterms from a BDD whose
support has n
variables at most. The procedure tries
to create as few extra nodes as possible. The function represented
by S
depends on at most n
of the variables
in xVars
. Returns a BDD with m
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) {
FREE(varSeen);
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)) {
if (!st_lookup(mtable, Nv, &dummy)) return(NULL);
numT = *dummy/(2*(1<
Internal procedures included in this module:
Static procedures included in this module:
]
SeeAlso [cuddSubsetSP.c]
Author [Kavita Ravi]
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#ifdef __STDC__
#include
Internal procedures included in this module:
Static procedures included in this module:
]
SeeAlso [cuddSubsetHB.c]
Author [Kavita Ravi]
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#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 size to 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;
};
struct GlobalInfo {
struct NodeDist **nodeDistPages; /* pointers to the pages */
int nodeDistPageIndex; /* index to next element */
int nodeDistPage; /* index to current page */
int nodeDistPageSize; /* page size */
int maxNodeDistPages; /* number of page pointers */
struct NodeDist *currentNodeDistPage; /* current page */
DdNode ***queuePages; /* pointers to the pages */
int queuePageIndex; /* index to next element */
int queuePage; /* index to current page */
int queuePageSize; /* page size */
int maxQueuePages; /* number of page pointers */
DdNode **currentQueuePage; /* current page */
#ifdef DD_DEBUG
int numCalls;
int hits;
int thishit;
#endif
};
/*---------------------------------------------------------------------------*/
/* Type declarations */
/*---------------------------------------------------------------------------*/
typedef struct NodeDist NodeDist_t;
typedef struct GlobalInfo GlobalInfo_t;
/*---------------------------------------------------------------------------*/
/* Variable declarations */
/*---------------------------------------------------------------------------*/
#ifndef lint
static char rcsid[] DD_UNUSED = "$Id: cuddSubsetSP.c,v 1.36 2012/02/05 01:07:19 fabio Exp $";
#endif
/*---------------------------------------------------------------------------*/
/* Macro declarations */
/*---------------------------------------------------------------------------*/
#ifdef __cplusplus
extern "C" {
#endif
/**AutomaticStart*************************************************************/
/*---------------------------------------------------------------------------*/
/* Static function prototypes */
/*---------------------------------------------------------------------------*/
static void ResizeNodeDistPages (DdManager *dd, GlobalInfo_t *gInfo);
static void ResizeQueuePages (DdManager *dd, GlobalInfo_t *gInfo);
static void CreateTopDist (DdManager *dd, GlobalInfo_t *gInfo, st_table *pathTable, int parentPage, int parentQueueIndex, int topLen, DdNode **childPage, int childQueueIndex, int numParents, FILE *fp);
static int CreateBotDist (DdNode *node, st_table *pathTable, unsigned int *pathLengthArray, FILE *fp);
static st_table * CreatePathTable (DdManager *dd, GlobalInfo_t *gInfo, DdNode *node, unsigned int *pathLengthArray, FILE *fp);
static unsigned int AssessPathLength (unsigned int *pathLengthArray, int threshold, int numVars, unsigned int *excess, FILE *fp);
static DdNode * BuildSubsetBdd (DdManager *dd, GlobalInfo_t *gInfo, st_table *pathTable, DdNode *node, struct AssortedInfo *info, st_table *subsetNodeTable);
static enum st_retval stPathTableDdFree (char *key, char *value, char *arg);
/**AutomaticEnd***************************************************************/
#ifdef __cplusplus
}
#endif
/*---------------------------------------------------------------------------*/
/* 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;
do {
dd->reordered = 0;
subset = cuddSubsetShortPaths(dd, f, numVars, threshold, hardlimit);
} while(dd->reordered == 1);
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);
do {
dd->reordered = 0;
subset = cuddSubsetShortPaths(dd, g, numVars, threshold, hardlimit);
} while(dd->reordered == 1);
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 threshold should be respected strictly */)
{
GlobalInfo_t gInfo;
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;
gInfo.nodeDistPageSize = DEFAULT_NODE_DIST_PAGE_SIZE;
gInfo.queuePageSize = DEFAULT_PAGE_SIZE;
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
gInfo.numCalls = 0;
#endif
pathTable = CreatePathTable(dd, &gInfo, f, pathLengthArray, dd->err);
if ((pathTable == NULL) || (dd->errorCode == CUDD_MEMORY_OUT)) {
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, N, &nodeStat)) {
fprintf(dd->err, "Something wrong, root node must be in table\n");
dd->errorCode = CUDD_INTERNAL_ERROR;
FREE(excess);
FREE(info);
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 %u, %u\n", maxpath, pathLength);
dd->errorCode = CUDD_INTERNAL_ERROR;
return(NULL);
}
}
#ifdef DD_DEBUG
gInfo.numCalls = 0;
gInfo.hits = 0;
gInfo.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, &gInfo, 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",
gInfo.hits, gInfo.thishit, gInfo.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 <= gInfo.nodeDistPage; i++) FREE(gInfo.nodeDistPages[i]);
FREE(gInfo.nodeDistPages);
#ifdef DD_DEBUG
/* check containment of subset in f */
if (subset != NULL) {
if (!Cudd_bddLeq(dd, subset, f)) {
(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(
DdManager *dd /* DD manager */,
GlobalInfo_t *gInfo /* global information */)
{
int i;
NodeDist_t **newNodeDistPages;
/* move to next page */
gInfo->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 (gInfo->nodeDistPage == gInfo->maxNodeDistPages) {
newNodeDistPages = ALLOC(NodeDist_t *,gInfo->maxNodeDistPages + INITIAL_PAGES);
if (newNodeDistPages == NULL) {
for (i = 0; i < gInfo->nodeDistPage; i++) FREE(gInfo->nodeDistPages[i]);
FREE(gInfo->nodeDistPages);
dd->errorCode = CUDD_MEMORY_OUT;
return;
} else {
for (i = 0; i < gInfo->maxNodeDistPages; i++) {
newNodeDistPages[i] = gInfo->nodeDistPages[i];
}
/* Increase total page count */
gInfo->maxNodeDistPages += INITIAL_PAGES;
FREE(gInfo->nodeDistPages);
gInfo->nodeDistPages = newNodeDistPages;
}
}
/* Allocate a new page */
gInfo->currentNodeDistPage = gInfo->nodeDistPages[gInfo->nodeDistPage] =
ALLOC(NodeDist_t, gInfo->nodeDistPageSize);
if (gInfo->currentNodeDistPage == NULL) {
for (i = 0; i < gInfo->nodeDistPage; i++) FREE(gInfo->nodeDistPages[i]);
FREE(gInfo->nodeDistPages);
dd->errorCode = CUDD_MEMORY_OUT;
return;
}
/* reset page index */
gInfo->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(
DdManager *dd /* DD manager */,
GlobalInfo_t *gInfo /* global information */)
{
int i;
DdNode ***newQueuePages;
gInfo->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 (gInfo->queuePage == gInfo->maxQueuePages) {
newQueuePages = ALLOC(DdNode **,gInfo->maxQueuePages + INITIAL_PAGES);
if (newQueuePages == NULL) {
for (i = 0; i < gInfo->queuePage; i++) FREE(gInfo->queuePages[i]);
FREE(gInfo->queuePages);
dd->errorCode = CUDD_MEMORY_OUT;
return;
} else {
for (i = 0; i < gInfo->maxQueuePages; i++) {
newQueuePages[i] = gInfo->queuePages[i];
}
/* Increase total page count */
gInfo->maxQueuePages += INITIAL_PAGES;
FREE(gInfo->queuePages);
gInfo->queuePages = newQueuePages;
}
}
/* Allocate a new page */
gInfo->currentQueuePage = gInfo->queuePages[gInfo->queuePage] =
ALLOC(DdNode *,gInfo->queuePageSize);
if (gInfo->currentQueuePage == NULL) {
for (i = 0; i < gInfo->queuePage; i++) FREE(gInfo->queuePages[i]);
FREE(gInfo->queuePages);
dd->errorCode = CUDD_MEMORY_OUT;
return;
}
/* reset page index */
gInfo->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(
DdManager *dd /* DD manager */,
GlobalInfo_t *gInfo /* global information */,
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
gInfo->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 ((gInfo->queuePages[parentPage] == childPage) && (parentQueueIndex ==
childQueueIndex)) {
fprintf(fp, "Should not happen that they are equal\n");
}
assert(gInfo->queuePageIndex == childQueueIndex);
assert(gInfo->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 == gInfo->queuePageSize) {
parentPage++;
parentQueueIndex = 0;
}
/* a parent to process */
node = *(gInfo->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, regChild, &nodeStat)) {
/* if not in table, has never been visited */
/* create entry for table */
if (gInfo->nodeDistPageIndex == gInfo->nodeDistPageSize)
ResizeNodeDistPages(dd, gInfo);
if (dd->errorCode == CUDD_MEMORY_OUT) {
for (i = 0; i <= gInfo->queuePage; i++) FREE(gInfo->queuePages[i]);
FREE(gInfo->queuePages);
st_free_table(pathTable);
return;
}
/* New entry for child in path Table is created here */
nodeStat = gInfo->currentNodeDistPage + gInfo->nodeDistPageIndex;
gInfo->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, regChild,
nodeStat) == ST_OUT_OF_MEM) {
dd->errorCode = CUDD_MEMORY_OUT;
for (i = 0; i <= gInfo->nodeDistPage; i++)
FREE(gInfo->nodeDistPages[i]);
FREE(gInfo->nodeDistPages);
for (i = 0; i <= gInfo->queuePage; i++) FREE(gInfo->queuePages[i]);
FREE(gInfo->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 (gInfo->queuePageIndex == gInfo->queuePageSize) ResizeQueuePages(dd, gInfo);
if (dd->errorCode == CUDD_MEMORY_OUT) {
for (i = 0; i <= gInfo->nodeDistPage; i++)
FREE(gInfo->nodeDistPages[i]);
FREE(gInfo->nodeDistPages);
st_free_table(pathTable);
return;
}
*(gInfo->currentQueuePage + gInfo->queuePageIndex) = child;
gInfo->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 (gInfo->queuePageIndex == gInfo->queuePageSize) ResizeQueuePages(dd, gInfo);
if (dd->errorCode == CUDD_MEMORY_OUT) {
for (i = 0; i <= gInfo->nodeDistPage; i++)
FREE(gInfo->nodeDistPages[i]);
FREE(gInfo->nodeDistPages);
st_free_table(pathTable);
return;
}
*(gInfo->currentQueuePage + gInfo->queuePageIndex) = child;
gInfo->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(gInfo->queuePages[parentPage] == childPage);
assert(parentQueueIndex == childQueueIndex);
#endif
if (childrenCount != 0) {
topLen++;
childPage = gInfo->currentQueuePage;
childQueueIndex = gInfo->queuePageIndex;
CreateTopDist(dd, gInfo, 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, N, &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, regChild, &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(
DdManager *dd /* DD manager */,
GlobalInfo_t *gInfo /* global information */,
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 */
gInfo->maxNodeDistPages = INITIAL_PAGES;
gInfo->nodeDistPages = ALLOC(NodeDist_t *, gInfo->maxNodeDistPages);
if (gInfo->nodeDistPages == NULL) {
goto OUT_OF_MEM;
}
gInfo->nodeDistPage = 0;
gInfo->currentNodeDistPage = gInfo->nodeDistPages[gInfo->nodeDistPage] =
ALLOC(NodeDist_t, gInfo->nodeDistPageSize);
if (gInfo->currentNodeDistPage == NULL) {
for (i = 0; i <= gInfo->nodeDistPage; i++) FREE(gInfo->nodeDistPages[i]);
FREE(gInfo->nodeDistPages);
goto OUT_OF_MEM;
}
gInfo->nodeDistPageIndex = 0;
/* Initializing pages for the BFS search queue, implemented as an array. */
gInfo->maxQueuePages = INITIAL_PAGES;
gInfo->queuePages = ALLOC(DdNode **, gInfo->maxQueuePages);
if (gInfo->queuePages == NULL) {
goto OUT_OF_MEM;
}
gInfo->queuePage = 0;
gInfo->currentQueuePage = gInfo->queuePages[gInfo->queuePage] =
ALLOC(DdNode *, gInfo->queuePageSize);
if (gInfo->currentQueuePage == NULL) {
for (i = 0; i <= gInfo->queuePage; i++) FREE(gInfo->queuePages[i]);
FREE(gInfo->queuePages);
goto OUT_OF_MEM;
}
gInfo->queuePageIndex = 0;
/* Enter the root node into the queue to start with. */
parentPage = gInfo->queuePage;
parentQueueIndex = gInfo->queuePageIndex;
topLen = 0;
*(gInfo->currentQueuePage + gInfo->queuePageIndex) = node;
gInfo->queuePageIndex++;
childPage = gInfo->currentQueuePage;
childQueueIndex = gInfo->queuePageIndex;
N = Cudd_Regular(node);
if (gInfo->nodeDistPageIndex == gInfo->nodeDistPageSize) ResizeNodeDistPages(dd, gInfo);
if (dd->errorCode == CUDD_MEMORY_OUT) {
for (i = 0; i <= gInfo->nodeDistPage; i++) FREE(gInfo->nodeDistPages[i]);
FREE(gInfo->nodeDistPages);
for (i = 0; i <= gInfo->queuePage; i++) FREE(gInfo->queuePages[i]);
FREE(gInfo->queuePages);
st_free_table(pathTable);
goto OUT_OF_MEM;
}
nodeStat = gInfo->currentNodeDistPage + gInfo->nodeDistPageIndex;
gInfo->nodeDistPageIndex++;
nodeStat->oddTopDist = MAXSHORTINT;
nodeStat->evenTopDist = MAXSHORTINT;
nodeStat->evenBotDist = MAXSHORTINT;
nodeStat->oddBotDist = MAXSHORTINT;
nodeStat->regResult = NULL;
nodeStat->compResult = NULL;
insertValue = st_insert(pathTable, N, nodeStat);
if (insertValue == ST_OUT_OF_MEM) {
dd->errorCode = CUDD_MEMORY_OUT;
for (i = 0; i <= gInfo->nodeDistPage; i++) FREE(gInfo->nodeDistPages[i]);
FREE(gInfo->nodeDistPages);
for (i = 0; i <= gInfo->queuePage; i++) FREE(gInfo->queuePages[i]);
FREE(gInfo->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
gInfo->numCalls = 0;
#endif
CreateTopDist(dd, gInfo, pathTable, parentPage, parentQueueIndex, (int) topLen,
childPage, childQueueIndex, numParents, fp);
if (dd->errorCode == CUDD_MEMORY_OUT) {
fprintf(fp, "Out of Memory and cant count path lengths\n");
goto OUT_OF_MEM;
}
#ifdef DD_DEBUG
gInfo->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 <= gInfo->queuePage; i++) FREE(gInfo->queuePages[i]);
FREE(gInfo->queuePages);
return(pathTable);
OUT_OF_MEM:
(void) fprintf(fp, "Out of Memory, cannot allocate pages\n");
dd->errorCode = CUDD_MEMORY_OUT;
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 */,
GlobalInfo_t *gInfo /* global information */,
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;
DdNode *zero = Cudd_Not(DD_ONE(dd));
#ifdef DD_DEBUG
gInfo->numCalls++;
#endif
if (Cudd_IsConstant(node))
return(node);
N = Cudd_Regular(node);
/* Find node in table. */
if (!st_lookup(pathTable, N, &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
gInfo->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
gInfo->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, regNv, &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, regNnv, &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, gInfo, 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, regChild, &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, gInfo, 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, regChild,
NULL) == ST_OUT_OF_MEM) {
dd->errorCode = CUDD_MEMORY_OUT;
(void) fprintf(dd->err, "OUT of memory\n");
info->thresholdReached = 0;
childBranch = zero;
} else {
info->thresholdReached--;
childBranch = BuildSubsetBdd(dd, gInfo, 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, regChild,
NULL) == ST_OUT_OF_MEM) {
dd->errorCode = CUDD_MEMORY_OUT;
(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, gInfo, 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, regNew, &entry)) {
if (!Cudd_IsConstant(regNew)) {
if (st_insert(subsetNodeTable, regNew,
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
gInfo->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
gInfo->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 */
BRiAl-1.2.0/cudd/cuddSymmetry.c 0000664 0000000 0000000 00000141220 13173454145 0016226 0 ustar 00root root 0000000 0000000 /**CFile***********************************************************************
FileName [cuddSymmetry.c]
PackageName [cudd]
Synopsis [Functions for symmetry-based variable reordering.]
Description [External procedures included in this file:
Internal procedures included in this module:
Static procedures included in this module:
]
Author [Shipra Panda, Fabio Somenzi]
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#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.28 2012/02/05 01:07:19 fabio Exp $";
#endif
static int *entry;
extern int ddTotalNumberSwapping;
#ifdef DD_STATS
extern int ddTotalNISwaps;
#endif
/*---------------------------------------------------------------------------*/
/* Macro declarations */
/*---------------------------------------------------------------------------*/
/**AutomaticStart*************************************************************/
/*---------------------------------------------------------------------------*/
/* Static function prototypes */
/*---------------------------------------------------------------------------*/
static int ddSymmUniqueCompare (int *ptrX, int *ptrY);
static int ddSymmSiftingAux (DdManager *table, int x, int xLow, int xHigh);
static int ddSymmSiftingConvAux (DdManager *table, int x, int xLow, int xHigh);
static Move * ddSymmSiftingUp (DdManager *table, int y, int xLow);
static Move * ddSymmSiftingDown (DdManager *table, int x, int xHigh);
static int ddSymmGroupMove (DdManager *table, int x, int y, Move **moves);
static int ddSymmGroupMoveBackward (DdManager *table, int x, int y);
static int ddSymmSiftingBackward (DdManager *table, Move *moves, int size);
static void ddSymmSummary (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.
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),(DD_QSFP)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;
if (util_cpu_time() - table->startTime > table->timeLimit) {
table->autoDyn = 0; /* prevent further reordering */
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.
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),(DD_QSFP)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;
if (util_cpu_time() - table->startTime > table->timeLimit) {
table->autoDyn = 0; /* prevent further reordering */
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),(DD_QSFP)ddSymmUniqueCompare);
/* Now sift. */
for (i = 0; i < ddMin(table->siftMaxVar,classes); i++) {
if (ddTotalNumberSwapping >= table->siftMaxSwap)
break;
if (util_cpu_time() - table->startTime > table->timeLimit) {
table->autoDyn = 0; /* prevent further reordering */
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;
cuddDeallocMove(table, 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;
cuddDeallocMove(table, 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;
cuddDeallocMove(table, moveDown);
moveDown = move;
}
while (moveUp != NULL) {
move = moveUp->next;
cuddDeallocMove(table, moveUp);
moveUp = move;
}
return(1);
ddSymmSiftingAuxOutOfMem:
if (moveDown != MV_OOM) {
while (moveDown != NULL) {
move = moveDown->next;
cuddDeallocMove(table, moveDown);
moveDown = move;
}
}
if (moveUp != MV_OOM) {
while (moveUp != NULL) {
move = moveUp->next;
cuddDeallocMove(table, 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;
cuddDeallocMove(table, 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;
cuddDeallocMove(table, 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;
cuddDeallocMove(table, moveDown);
moveDown = move;
}
while (moveUp != NULL) {
move = moveUp->next;
cuddDeallocMove(table, moveUp);
moveUp = move;
}
return(1);
ddSymmSiftingConvAuxOutOfMem:
if (moveDown != MV_OOM) {
while (moveDown != NULL) {
move = moveDown->next;
cuddDeallocMove(table, moveDown);
moveDown = move;
}
}
if (moveUp != MV_OOM) {
while (moveUp != NULL) {
move = moveUp->next;
cuddDeallocMove(table, 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;
cuddDeallocMove(table, 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;
cuddDeallocMove(table, 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;
#ifdef 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;
#ifdef 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 */
BRiAl-1.2.0/cudd/cuddTable.c 0000664 0000000 0000000 00000275042 13173454145 0015436 0 ustar 00root root 0000000 0000000 /**CFile***********************************************************************
FileName [cuddTable.c]
PackageName [cudd]
Synopsis [Unique table management functions.]
Description [External procedures included in this module:
Internal procedures included in this module:
Static procedures included in this module:
]
SeeAlso []
Author [Fabio Somenzi]
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#include "util.h"
#include "cuddInt.h"
#ifndef PBORI_FORCE_ORIGINAL_CUDD
#include
Internal procedures included in this module:
Static procedures included in this module:
]
Author [Fabio Somenzi]
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#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.83 2012/02/05 01:07:19 fabio 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)) ? '!' : ' ')
#ifdef __cplusplus
extern "C" {
#endif
/**AutomaticStart*************************************************************/
/*---------------------------------------------------------------------------*/
/* Static function prototypes */
/*---------------------------------------------------------------------------*/
static int dp2 (DdManager *dd, DdNode *f, st_table *t);
static void ddPrintMintermAux (DdManager *dd, DdNode *node, int *list);
static int ddDagInt (DdNode *n);
static int cuddNodeArrayRecur (DdNode *f, DdNodePtr *table, int index);
static int cuddEstimateCofactor (DdManager *dd, st_table *table, DdNode * node, int i, int phase, DdNode ** ptr);
static DdNode * cuddUniqueLookup (DdManager * unique, int index, DdNode * T, DdNode * E);
static int cuddEstimateCofactorSimple (DdNode * node, int i);
static double ddCountMintermAux (DdNode *node, double max, DdHashTable *table);
static int ddEpdCountMintermAux (DdNode *node, EpDouble *max, EpDouble *epd, st_table *table);
static double ddCountPathAux (DdNode *node, st_table *table);
static double ddCountPathsToNonZero (DdNode * N, st_table * table);
static void ddSupportStep (DdNode *f, int *support);
static void ddClearFlag (DdNode *f);
static int ddLeavesInt (DdNode *n);
static int ddPickArbitraryMinterms (DdManager *dd, DdNode *node, int nvars, int nminterms, char **string);
static int ddPickRepresentativeCube (DdManager *dd, DdNode *node, double *weight, char *string);
static enum st_retval ddEpdFree (char * key, char * value, char * arg);
static void ddFindSupport(DdManager *dd, DdNode *f, int *SP);
static void ddClearVars(DdManager *dd, int SP);
static int indexCompare(const void *a, const void *b);
/**AutomaticEnd***************************************************************/
#ifdef __cplusplus
}
#endif
/*---------------------------------------------------------------------------*/
/* 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 */
#ifdef PBORI_FORCE_ORIGINAL_CUDD
/**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 */
#endif
/**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 > 0. Specifically:
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 not create any new node.
It does keep a small table of results; therefore it may 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 */
#ifdef PBORI_FORCE_ORIGINAL_CUDD
/**Function********************************************************************
Synopsis [Finds the variables on which a DD depends.]
Description [Finds the variables on which a DD depends. Returns the
number of variables if successful; CUDD_OUT_OF_MEM otherwise.]
SideEffects [The indices of the support variables are returned as
side effects. If the function is constant, no array is allocated.]
SeeAlso [Cudd_Support Cudd_SupportIndex Cudd_VectorSupportIndices]
******************************************************************************/
int
Cudd_SupportIndices(
DdManager * dd /* manager */,
DdNode * f /* DD whose support is sought */,
int **indices /* array containing (on return) the indices */)
{
int SP = 0;
ddFindSupport(dd, Cudd_Regular(f), &SP);
ddClearFlag(Cudd_Regular(f));
ddClearVars(dd, SP);
if (SP > 0) {
int i;
*indices = ALLOC(int, SP);
if (*indices == NULL) {
dd->errorCode = CUDD_MEMORY_OUT;
return(CUDD_OUT_OF_MEM);
}
for (i = 0; i < SP; i++)
(*indices)[i] = (int) (ptrint) dd->stack[i];
qsort(*indices, SP, sizeof(int), indexCompare);
} else {
*indices = NULL;
}
return(SP);
} /* end of Cudd_SupportIndices */
/**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;
int j;
int size = Cudd_SupportIndices(dd, f, &support);
if (size == CUDD_OUT_OF_MEM)
return(NULL);
/* Transform support from array of indices to cube. */
res = DD_ONE(dd);
cuddRef(res);
for (j = size - 1; j >= 0; j--) { /* for each index bottom-up (almost) */
int index = support[j];
DdNode *var = dd->vars[index];
DdNode *tmp = Cudd_bddAnd(dd,res,var);
if (tmp == NULL) {
Cudd_RecursiveDeref(dd,res);
FREE(support);
return(NULL);
}
cuddRef(tmp);
Cudd_RecursiveDeref(dd,res);
res = tmp;
}
FREE(support);
cuddDeref(res);
return(res);
} /* end of Cudd_Support */
#endif
/**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. The
size of the array equals the number of variables in the manager.
Each entry of the array is 1 if the corresponding variable is in the
support of the DD and 0 otherwise.]
SideEffects [None]
SeeAlso [Cudd_Support Cudd_SupportIndices 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 [Returns the variables on which a DD depends.]
SideEffects [None]
SeeAlso [Cudd_Support Cudd_SupportIndices]
******************************************************************************/
int
Cudd_SupportSize(
DdManager * dd /* manager */,
DdNode * f /* DD whose support size is sought */)
{
int SP = 0;
ddFindSupport(dd, Cudd_Regular(f), &SP);
ddClearFlag(Cudd_Regular(f));
ddClearVars(dd, SP);
return(SP);
} /* 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 the number
of variables if successful; CUDD_OUT_OF_MEM otherwise.]
SideEffects [The indices of the support variables are returned as
side effects. If the function is constant, no array is allocated.]
SeeAlso [Cudd_Support Cudd_SupportIndex Cudd_VectorSupportIndices]
******************************************************************************/
int
Cudd_VectorSupportIndices(
DdManager * dd /* manager */,
DdNode ** F /* DD whose support is sought */,
int n /* size of the array */,
int **indices /* array containing (on return) the indices */)
{
int i;
int SP = 0;
/* Compute support and clean up markers. */
for (i = 0; i < n; i++) {
ddFindSupport(dd, Cudd_Regular(F[i]), &SP);
}
for (i = 0; i < n; i++) {
ddClearFlag(Cudd_Regular(F[i]));
}
ddClearVars(dd, SP);
if (SP > 0) {
int i;
*indices = ALLOC(int, SP);
if (*indices == NULL) {
dd->errorCode = CUDD_MEMORY_OUT;
return(CUDD_OUT_OF_MEM);
}
for (i = 0; i < SP; i++)
(*indices)[i] = (int) (ptrint) dd->stack[i];
qsort(*indices, SP, sizeof(int), indexCompare);
} else {
*indices = NULL;
}
return(SP);
} /* end of Cudd_VectorSupportIndices */
#ifdef PBORI_FORCE_ORIGINAL_CUDD
/**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;
int j;
int size = Cudd_VectorSupportIndices(dd, F, n, &support);
if (size == CUDD_OUT_OF_MEM)
return(NULL);
/* Transform support from array of indices to cube. */
res = DD_ONE(dd);
cuddRef(res);
for (j = size - 1; j >= 0; j--) { /* for each index bottom-up (almost) */
int index = support[j];
DdNode *var = dd->vars[index];
DdNode *tmp = Cudd_bddAnd(dd,res,var);
if (tmp == NULL) {
Cudd_RecursiveDeref(dd,res);
FREE(support);
return(NULL);
}
cuddRef(tmp);
Cudd_RecursiveDeref(dd,res);
res = tmp;
}
FREE(support);
cuddDeref(res);
return(res);
} /* end of Cudd_VectorSupport */
#endif
/**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_VectorSupportIndices]
******************************************************************************/
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 [Returns the variables on which a set of DDs depends.
The set must contain either BDDs and ADDs, or ZDDs.]
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 i;
int SP = 0;
/* Compute support and clean up markers. */
for (i = 0; i < n; i++) {
ddFindSupport(dd, Cudd_Regular(F[i]), &SP);
}
for (i = 0; i < n; i++) {
ddClearFlag(Cudd_Regular(F[i]));
}
ddClearVars(dd, SP);
return(SP);
} /* end of Cudd_VectorSupportSize */
#ifdef PBORI_FORCE_ORIGINAL_CUDD
/**Function********************************************************************
Synopsis [Classifies the variables in the support of two DDs.]
Description [Classifies the variables in the support of two DDs
f
and g
, depending on whther they appear
in both DDs, only in f
, or only in g
.
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;
int fi, gi;
int sizeF, sizeG;
sizeF = Cudd_SupportIndices(dd, f, &supportF);
if (sizeF == CUDD_OUT_OF_MEM)
return(0);
sizeG = Cudd_SupportIndices(dd, g, &supportG);
if (sizeG == CUDD_OUT_OF_MEM) {
FREE(supportF);
return(0);
}
/* Classify variables and create cubes. This part of the procedure
** relies on the sorting of the indices in the two support arrays.
*/
*common = *onlyF = *onlyG = DD_ONE(dd);
cuddRef(*common); cuddRef(*onlyF); cuddRef(*onlyG);
fi = sizeF - 1;
gi = sizeG - 1;
while (fi >= 0 || gi >= 0) {
int indexF = fi >= 0 ? supportF[fi] : -1;
int indexG = gi >= 0 ? supportG[gi] : -1;
int index = ddMax(indexF, indexG);
DdNode *var = dd->vars[index];
#ifdef DD_DEBUG
assert(index >= 0);
#endif
if (indexF == indexG) {
DdNode *tmp = Cudd_bddAnd(dd,*common,var);
if (tmp == NULL) {
Cudd_RecursiveDeref(dd,*common);
Cudd_RecursiveDeref(dd,*onlyF);
Cudd_RecursiveDeref(dd,*onlyG);
FREE(supportF); FREE(supportG);
return(0);
}
cuddRef(tmp);
Cudd_RecursiveDeref(dd,*common);
*common = tmp;
fi--;
gi--;
} else if (index == indexF) {
DdNode *tmp = Cudd_bddAnd(dd,*onlyF,var);
if (tmp == NULL) {
Cudd_RecursiveDeref(dd,*common);
Cudd_RecursiveDeref(dd,*onlyF);
Cudd_RecursiveDeref(dd,*onlyG);
FREE(supportF); FREE(supportG);
return(0);
}
cuddRef(tmp);
Cudd_RecursiveDeref(dd,*onlyF);
*onlyF = tmp;
fi--;
} else { /* index == indexG */
DdNode *tmp = Cudd_bddAnd(dd,*onlyG,var);
if (tmp == NULL) {
Cudd_RecursiveDeref(dd,*common);
Cudd_RecursiveDeref(dd,*onlyF);
Cudd_RecursiveDeref(dd,*onlyG);
FREE(supportF); FREE(supportG);
return(0);
}
cuddRef(tmp);
Cudd_RecursiveDeref(dd,*onlyG);
*onlyG = tmp;
gi--;
}
}
FREE(supportF); FREE(supportG);
cuddDeref(*common); cuddDeref(*onlyF); cuddDeref(*onlyG);
return(1);
} /* end of Cudd_ClassifySupport */
#endif
/**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 */
#ifdef PBORI_FORCE_ORIGINAL_CUDD
/**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 vars
. The array
vars
should contain at least all variables in the
support of f
; if this condition is not met the minterm
built by this procedure may not be contained in
f
. 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:
]
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 f
may be the constant 0;
f
.
vars
*/)
{
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 */
#endif
#ifdef PBORI_FORCE_ORIGINAL_CUDD
/**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 vars
. The array
vars
should contain at least all variables in the
support of f
; if this condition is not met the minterms
built by this procedure may not be contained in
f
. 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:
]
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 f
may be the constant 0;
f
.
vars
*/,
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]] =
(char) ((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]] =
(char) ((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 */
#endif
#ifdef PBORI_FORCE_ORIGINAL_CUDD
/**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 vars
*/,
DdNode ** maskVars /* array of variables */,
int mvars /* size of maskVars
*/)
{
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;
FREE(weight);
return(NULL);
}
mask = ALLOC(int, size);
if (mask == NULL) {
dd->errorCode = CUDD_MEMORY_OUT;
FREE(weight);
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(weight);
FREE(string);
FREE(mask);
return(NULL);
}
for (i = 0; i < nvars; i++) {
indices[i] = vars[i]->index;
}
result = ddPickRepresentativeCube(dd,f,weight,string);
if (result == 0) {
FREE(weight);
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(weight);
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(weight);
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(weight);
FREE(string);
FREE(mask);
FREE(indices);
return(subset);
} /* end of Cudd_SubsetWithMaskVars */
#endif
/**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.
Static procedures included in this module:
]
Author [Fabio Somenzi]
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#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.15 2012/02/05 01:07:19 fabio Exp $";
#endif
#ifdef DD_STATS
extern int ddTotalNumberSwapping;
extern int ddTotalNISwaps;
#endif
/*---------------------------------------------------------------------------*/
/* Macro declarations */
/*---------------------------------------------------------------------------*/
/**AutomaticStart*************************************************************/
/*---------------------------------------------------------------------------*/
/* Static function prototypes */
/*---------------------------------------------------------------------------*/
static int ddWindow2 (DdManager *table, int low, int high);
static int ddWindowConv2 (DdManager *table, int low, int high);
static int ddPermuteWindow3 (DdManager *table, int x);
static int ddWindow3 (DdManager *table, int low, int high);
static int ddWindowConv3 (DdManager *table, int low, int high);
static int ddPermuteWindow4 (DdManager *table, int w);
static int ddWindow4 (DdManager *table, int low, int high);
static int ddWindowConv4 (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
Internal procedures included in this module:
Static procedures included in this module:
]
SeeAlso []
Author [Hyong-Kyoon Shin, In-Ho Moon]
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#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.15 2012/02/05 01:07:19 fabio Exp $";
#endif
/*---------------------------------------------------------------------------*/
/* Macro declarations */
/*---------------------------------------------------------------------------*/
#ifdef __cplusplus
extern "C" {
#endif
/**AutomaticStart*************************************************************/
/*---------------------------------------------------------------------------*/
/* Static function prototypes */
/*---------------------------------------------------------------------------*/
static int cuddZddCountStep (DdNode *P, st_table *table, DdNode *base, DdNode *empty);
static double cuddZddCountDoubleStep (DdNode *P, st_table *table, DdNode *base, DdNode *empty);
static enum st_retval st_zdd_countfree (char *key, char *value, char *arg);
static enum st_retval st_zdd_count_dbl_free (char *key, char *value, char *arg);
/**AutomaticEnd***************************************************************/
#ifdef __cplusplus
}
#endif
/*---------------------------------------------------------------------------*/
/* 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, P, &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, P, &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 */
BRiAl-1.2.0/cudd/cuddZddFuncs.c 0000664 0000000 0000000 00000120164 13173454145 0016121 0 ustar 00root root 0000000 0000000 /**CFile***********************************************************************
FileName [cuddZddFuncs.c]
PackageName [cudd]
Synopsis [Functions to manipulate covers represented as ZDDs.]
Description [External procedures included in this module:
Internal procedures included in this module:
Static procedures included in this module:
]
SeeAlso []
Author [In-Ho Moon]
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#include "util.h"
#include "cuddInt.h"
#ifndef PBORI_FORCE_ORIGINAL_CUDD
#include
Internal procedures included in this file:
Static procedures included in this module:
]
Author [Fabio Somenzi]
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#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.22 2012/02/05 01:07:19 fabio 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 (DdManager *table, MtrNode *treenode, Cudd_ReorderingType method);
#ifdef DD_STATS
static int zddCountInternalMtrNodes (DdManager *table, MtrNode *treenode);
#endif
static int zddReorderChildren (DdManager *table, MtrNode *treenode, Cudd_ReorderingType method);
static void zddFindNodeHiLo (DdManager *table, MtrNode *treenode, int *lower, int *upper);
static int zddUniqueCompareGroup (int *ptrX, int *ptrY);
static int zddGroupSifting (DdManager *table, int lower, int upper);
static int zddGroupSiftingAux (DdManager *table, int x, int xLow, int xHigh);
static int zddGroupSiftingUp (DdManager *table, int y, int xLow, Move **moves);
static int zddGroupSiftingDown (DdManager *table, int x, int xHigh, Move **moves);
static int zddGroupMove (DdManager *table, int x, int y, Move **moves);
static int zddGroupMoveBackward (DdManager *table, int x, int y);
static int zddGroupSiftingBackward (DdManager *table, Move *moves, int size);
static void zddMergeGroups (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),(DD_QSFP)zddUniqueCompareGroup);
/* Now sift. */
for (i = 0; i < ddMin(table->siftMaxVar,classes); i++) {
if (zddTotalNumberSwapping >= table->siftMaxSwap)
break;
if (util_cpu_time() - table->startTime > table->timeLimit) {
table->autoDynZ = 0; /* prevent further reordering */
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;
cuddDeallocMove(table, moves);
moves = move;
}
return(1);
zddGroupSiftingAuxOutOfMem:
while (moves != NULL) {
move = moves->next;
cuddDeallocMove(table, 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;
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 */
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;
cuddDeallocMove(table, *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 gybot;
/* Initialize R */
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;
cuddDeallocMove(table, *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
#ifdef 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;
cuddDeallocMove(table, *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;
#ifdef 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 */
BRiAl-1.2.0/cudd/cuddZddIsop.c 0000664 0000000 0000000 00000062003 13173454145 0015752 0 ustar 00root root 0000000 0000000 /**CFile***********************************************************************
FileName [cuddZddIsop.c]
PackageName [cudd]
Synopsis [Functions to find irredundant SOP covers as ZDDs from BDDs.]
Description [External procedures included in this module:
Internal procedures included in this module:
Static procedures included in this module:
]
SeeAlso []
Author [In-Ho Moon]
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#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.22 2012/02/05 01:07:19 fabio 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 i
should have indices 2i
and
2i+1
. 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-product cover.]
Description [Computes a BDD in the interval between L and U with a
simple sum-of-product 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.]
Description [Converts a ZDD cover to a BDD for the function represented
by the cover. If successful, it returns a BDD node, otherwise it returns
NULL.]
SideEffects []
SeeAlso [Cudd_zddIsop]
******************************************************************************/
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;
DD_CTFP cacheOp;
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 = (DD_CTFP) 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.]
Description [Converts a ZDD cover to a BDD. If successful, it returns
a BDD node, otherwise it returns NULL. It is a recursive algorithm
that works as follows. First it computes 3 cofactors of a ZDD cover:
f1, f0 and fd. Second, it compute BDDs (b1, b0 and bd) of f1, f0 and fd.
Third, it computes T=b1+bd and E=b0+bd. Fourth, it computes 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 the one of T
or the one of E, cuddUniqueInterIVO is called, where IVO stands for
independent from 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 */
if (cuddZddGetCofactors3(dd, node, v, &f1, &f0, &fd)) return(NULL);
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 (!b0) {
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 */
/*---------------------------------------------------------------------------*/
BRiAl-1.2.0/cudd/cuddZddLin.c 0000664 0000000 0000000 00000067034 13173454145 0015573 0 ustar 00root root 0000000 0000000 /**CFile***********************************************************************
FileName [cuddZddLin.c]
PackageName [cudd]
Synopsis [Procedures for dynamic variable ordering of ZDDs.]
Description [Internal procedures included in this module:
Static procedures included in this module:
]
SeeAlso [cuddLinear.c cuddZddReord.c]
Author [Fabio Somenzi]
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#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.16 2012/02/05 01:07:19 fabio Exp $";
#endif
extern int *zdd_entry;
extern int zddTotalNumberSwapping;
static int zddTotalNumberLinearTr;
static DdNode *empty;
/*---------------------------------------------------------------------------*/
/* Macro declarations */
/*---------------------------------------------------------------------------*/
/**AutomaticStart*************************************************************/
/*---------------------------------------------------------------------------*/
/* Static function prototypes */
/*---------------------------------------------------------------------------*/
static int cuddZddLinearInPlace (DdManager * table, int x, int y);
static int cuddZddLinearAux (DdManager *table, int x, int xLow, int xHigh);
static Move * cuddZddLinearUp (DdManager *table, int y, int xLow, Move *prevMoves);
static Move * cuddZddLinearDown (DdManager *table, int x, int xHigh, Move *prevMoves);
static int cuddZddLinearBackward (DdManager *table, int size, Move *moves);
static Move* cuddZddUndoMoves (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.
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), (DD_QSFP)cuddZddUniqueCompare);
/* Now sift. */
for (i = 0; i < ddMin(table->siftMaxVar, size); i++) {
if (zddTotalNumberSwapping >= table->siftMaxSwap)
break;
if (util_cpu_time() - table->startTime > table->timeLimit) {
table->autoDynZ = 0; /* prevent further reordering */
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 < y. Returns the
number of keys in the table if successful; 0 otherwise.]
SideEffects [None]
SeeAlso [cuddZddSwapInPlace cuddLinearInPlace]
******************************************************************************/
static 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;
cuddDeallocMove(table, moveDown);
moveDown = move;
}
while (moveUp != NULL) {
move = moveUp->next;
cuddDeallocMove(table, moveUp);
moveUp = move;
}
return(1);
cuddZddLinearAuxOutOfMem:
if (moveDown != (Move *) CUDD_OUT_OF_MEM) {
while (moveDown != NULL) {
move = moveDown->next;
cuddDeallocMove(table, moveDown);
moveDown = move;
}
}
if (moveUp != (Move *) CUDD_OUT_OF_MEM) {
while (moveUp != NULL) {
move = moveUp->next;
cuddDeallocMove(table, 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;
cuddDeallocMove(table, 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;
cuddDeallocMove(table, 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;
cuddDeallocMove(table, invmoves);
invmoves = move;
}
return((Move *) CUDD_OUT_OF_MEM);
} /* end of cuddZddUndoMoves */
BRiAl-1.2.0/cudd/cuddZddMisc.c 0000664 0000000 0000000 00000020731 13173454145 0015735 0 ustar 00root root 0000000 0000000 /**CFile***********************************************************************
FileName [cuddZddMisc.c]
PackageName [cudd]
Synopsis [Miscellaneous utility functions for ZDDs.]
Description [External procedures included in this module:
Internal procedures included in this module:
Static procedures included in this module:
]
SeeAlso []
Author [Hyong-Kyoon Shin, In-Ho Moon]
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#include node
. This procedure takes a parameter
path
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 = %u\tr = %u\t",
(ptruint) z1 / (ptruint) sizeof(DdNode),
z1->index, z1->ref);
#else
"ID = 0x%x\tindex = %hu\tr = %hu\t",
(ptruint) z1 / (ptruint) 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",
(ptruint) z1_next / (ptruint) sizeof(DdNode));
#else
(void) fprintf(table->out, "T = 0x%x\t",
(ptruint) z1_next / (ptruint) 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",
(ptruint) z1_next / (ptruint) sizeof(DdNode));
#else
(void) fprintf(table->out, "E = 0x%x\n",
(ptruint) z1_next / (ptruint) 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 */
BRiAl-1.2.0/cudd/cuddZddPort.c 0000664 0000000 0000000 00000025334 13173454145 0015772 0 ustar 00root root 0000000 0000000 /**CFile***********************************************************************
FileName [cuddZddPort.c]
PackageName [cudd]
Synopsis [Functions that translate BDDs to ZDDs.]
Description [External procedures included in this module:
Internal procedures included in this module:
Static procedures included in this module:
]
SeeAlso []
Author [Hyong-kyoon Shin, In-Ho Moon]
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#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.14 2012/02/05 01:07:19 fabio Exp $";
#endif
/*---------------------------------------------------------------------------*/
/* Macro declarations */
/*---------------------------------------------------------------------------*/
/**AutomaticStart*************************************************************/
/*---------------------------------------------------------------------------*/
/* Static function prototypes */
/*---------------------------------------------------------------------------*/
static DdNode * zddPortFromBddStep (DdManager *dd, DdNode *B, int expected);
static DdNode * zddPortToBddStep (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 */
BRiAl-1.2.0/cudd/cuddZddReord.c 0000664 0000000 0000000 00000130532 13173454145 0016116 0 ustar 00root root 0000000 0000000 /**CFile***********************************************************************
FileName [cuddZddReord.c]
PackageName [cudd]
Synopsis [Procedures for dynamic variable ordering of ZDDs.]
Description [External procedures included in this module:
Internal procedures included in this module:
Static procedures included in this module:
]
SeeAlso []
Author [Hyong-Kyoon Shin, In-Ho Moon]
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#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.49 2012/02/05 01:07:19 fabio Exp $";
#endif
int *zdd_entry;
int zddTotalNumberSwapping;
static DdNode *empty;
/*---------------------------------------------------------------------------*/
/* Macro declarations */
/*---------------------------------------------------------------------------*/
/**AutomaticStart*************************************************************/
/*---------------------------------------------------------------------------*/
/* Static function prototypes */
/*---------------------------------------------------------------------------*/
static Move * zddSwapAny (DdManager *table, int x, int y);
static int cuddZddSiftingAux (DdManager *table, int x, int x_low, int x_high);
static Move * cuddZddSiftingUp (DdManager *table, int x, int x_low, int initial_size);
static Move * cuddZddSiftingDown (DdManager *table, int x, int x_high, int initial_size);
static int cuddZddSiftingBackward (DdManager *table, Move *moves, int size);
static void zddReorderPreprocess (DdManager *table);
static int zddReorderPostprocess (DdManager *table);
static int zddShuffle (DdManager *table, int *permutation);
static int zddSiftUp (DdManager *table, int x, int xLow);
static void zddFixTree (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:
For sifting and symmetric sifting it is possible to request reordering
to convergence.M
be the ratio of the two numbers. cuddZddAlignToBdd
then considers the ZDD variables from M*i
to
(M+1)*i-1
as corresponding to BDD variable
i
. 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.
*/
cuddGarbageCollect(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 < 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.
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;
cuddDeallocMove(table, 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;
cuddDeallocMove(table, 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.
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), (DD_QSFP)cuddZddUniqueCompare);
/* Now sift. */
for (i = 0; i < ddMin(table->siftMaxVar, size); i++) {
if (zddTotalNumberSwapping >= table->siftMaxSwap)
break;
if (util_cpu_time() - table->startTime > table->timeLimit) {
table->autoDynZ = 0; /* prevent further reordering */
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;
cuddDeallocMove(table, 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;
cuddDeallocMove(table, moveDown);
moveDown = move;
}
while (moveUp != NULL) {
move = moveUp->next;
cuddDeallocMove(table, moveUp);
moveUp = move;
}
return(1);
cuddZddSiftingAuxOutOfMem:
while (moveDown != NULL) {
move = moveDown->next;
cuddDeallocMove(table, moveDown);
moveDown = move;
}
while (moveUp != NULL) {
move = moveUp->next;
cuddDeallocMove(table, 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;
cuddDeallocMove(table, 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;
cuddDeallocMove(table, 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. */
cuddGarbageCollect(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 DD_OOMFP MMoutOfMemory;
DD_OOMFP saveHandler;
#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
unsigned 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 */
BRiAl-1.2.0/cudd/cuddZddSetop.c 0000664 0000000 0000000 00000067415 13173454145 0016146 0 ustar 00root root 0000000 0000000 /**CFile***********************************************************************
FileName [cuddZddSetop.c]
PackageName [cudd]
Synopsis [Set operations on ZDDs.]
Description [External procedures included in this module:
Internal procedures included in this module:
Static procedures included in this module:
]
SeeAlso []
Author [Hyong-Kyoon Shin, In-Ho Moon]
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#include "util.h"
#include "cuddInt.h"
#ifndef PBORI_FORCE_ORIGINAL_CUDD
#include
Internal procedures included in this module:
Static procedures included in this module:
]
SeeAlso [cuddSymmetry.c]
Author [Hyong-Kyoon Shin, In-Ho Moon]
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#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.31 2012/02/05 01:07:19 fabio Exp $";
#endif
extern int *zdd_entry;
extern int zddTotalNumberSwapping;
static DdNode *empty;
/*---------------------------------------------------------------------------*/
/* Macro declarations */
/*---------------------------------------------------------------------------*/
/**AutomaticStart*************************************************************/
/*---------------------------------------------------------------------------*/
/* Static function prototypes */
/*---------------------------------------------------------------------------*/
static int cuddZddSymmSiftingAux (DdManager *table, int x, int x_low, int x_high);
static int cuddZddSymmSiftingConvAux (DdManager *table, int x, int x_low, int x_high);
static Move * cuddZddSymmSifting_up (DdManager *table, int x, int x_low, int initial_size);
static Move * cuddZddSymmSifting_down (DdManager *table, int x, int x_high, int initial_size);
static int cuddZddSymmSiftingBackward (DdManager *table, Move *moves, int size);
static int zdd_group_move (DdManager *table, int x, int y, Move **moves);
static int zdd_group_move_backward (DdManager *table, int x, int y);
static void cuddZddSymmSummary (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;
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.
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), (DD_QSFP)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;
if (util_cpu_time() - table->startTime > table->timeLimit) {
table->autoDynZ = 0; /* prevent further reordering */
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.
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), (DD_QSFP)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;
if (util_cpu_time() - table->startTime > table->timeLimit) {
table->autoDynZ = 0; /* prevent further reordering */
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),(DD_QSFP)cuddZddUniqueCompare);
/* Now sift. */
iteration = ddMin(table->siftMaxVar, nvars);
for (i = 0; i < iteration; i++) {
if (zddTotalNumberSwapping >= table->siftMaxSwap)
break;
if (util_cpu_time() - table->startTime > table->timeLimit) {
table->autoDynZ = 0; /* prevent further reordering */
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;
cuddDeallocMove(table, 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;
cuddDeallocMove(table, 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;
cuddDeallocMove(table, move_down);
move_down = move;
}
while (move_up != NULL) {
move = move_up->next;
cuddDeallocMove(table, move_up);
move_up = move;
}
return(1);
cuddZddSymmSiftingAuxOutOfMem:
if (move_down != ZDD_MV_OOM) {
while (move_down != NULL) {
move = move_down->next;
cuddDeallocMove(table, move_down);
move_down = move;
}
}
if (move_up != ZDD_MV_OOM) {
while (move_up != NULL) {
move = move_up->next;
cuddDeallocMove(table, 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;
cuddDeallocMove(table, 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;
cuddDeallocMove(table, 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;
cuddDeallocMove(table, move_down);
move_down = move;
}
while (move_up != NULL) {
move = move_up->next;
cuddDeallocMove(table, move_up);
move_up = move;
}
return(1);
cuddZddSymmSiftingConvAuxOutOfMem:
if (move_down != ZDD_MV_OOM) {
while (move_down != NULL) {
move = move_down->next;
cuddDeallocMove(table, move_down);
move_down = move;
}
}
if (move_up != ZDD_MV_OOM) {
while (move_up != NULL) {
move = move_up->next;
cuddDeallocMove(table, 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;
cuddDeallocMove(table, 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;
cuddDeallocMove(table, 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, 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;
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;
cuddDeallocMove(table, *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, 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;
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 */
BRiAl-1.2.0/cudd/cuddZddUtil.c 0000664 0000000 0000000 00000103555 13173454145 0015765 0 ustar 00root root 0000000 0000000 /**CFile***********************************************************************
FileName [cuddZddUtil.c]
PackageName [cudd]
Synopsis [Utility functions for ZDDs.]
Description [External procedures included in this module:
Internal procedures included in this module:
Static procedures included in this module:
]
SeeAlso []
Author [Hyong-Kyoon Shin, In-Ho Moon, Fabio Somenzi]
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#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.29 2012/02/05 01:07:19 fabio Exp $";
#endif
/*---------------------------------------------------------------------------*/
/* Macro declarations */
/*---------------------------------------------------------------------------*/
/**AutomaticStart*************************************************************/
/*---------------------------------------------------------------------------*/
/* Static function prototypes */
/*---------------------------------------------------------------------------*/
static int zp2 (DdManager *zdd, DdNode *f, st_table *t);
static void zdd_print_minterm_aux (DdManager *zdd, DdNode *node, int level, int *list);
static void zddPrintCoverAux (DdManager *zdd, DdNode *node, int level, int *list);
static void zddSupportStep(DdNode * f, int * support);
static void zddClearFlag(DdNode * f);
/**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 > 0. Specifically:
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.
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_zddSupport(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, &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,"\"%p\";\n", (void *)
((mask & (ptrint) 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,"\"%p\";\n", (void *)
((mask & (ptrint) 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," -> \"%p\" [style = solid];\n",
(void *) ((mask & (ptrint) 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,
"\"%p\" -> \"%p\";\n",
(void *) ((mask & (ptrint) scan) / sizeof(DdNode)),
(void *) ((mask & (ptrint) cuddT(scan)) /
sizeof(DdNode)));
if (retval == EOF) goto failure;
retval = fprintf(fp,
"\"%p\" -> \"%p\" [style = dashed];\n",
(void *) ((mask & (ptrint) scan)
/ sizeof(DdNode)),
(void *) ((mask & (ptrint)
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,"\"%p\" [label = \"%g\"];\n",
(void *) ((mask & (ptrint) 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 (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 = %u\tr = %u\t",
(ptruint)f / (ptruint) sizeof(DdNode), f->index, f->ref);
#else
(void) fprintf(zdd->out, "ID = 0x%x\tindex = %hu\tr = %hu\t",
(ptruint)f / (ptruint) 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", (ptruint) n /
(ptruint) sizeof(DdNode));
#else
(void) fprintf(zdd->out, "T = 0x%x\t", (ptruint) n /
(ptruint) 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", (ptruint) n /
(ptruint) sizeof(DdNode));
#else
(void) fprintf(zdd->out, "E = 0x%x\n", (ptruint) n /
(ptruint) 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 */
/**Function********************************************************************
Synopsis [Performs the recursive step of Cudd_zddSupport.]
Description [Performs the recursive step of Cudd_zddSupport. 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 [zddClearFlag]
******************************************************************************/
static void
zddSupportStep(
DdNode * f,
int * support)
{
if (cuddIsConstant(f) || Cudd_IsComplement(f->next)) {
return;
}
support[f->index] = 1;
zddSupportStep(cuddT(f),support);
zddSupportStep(Cudd_Regular(cuddE(f)),support);
/* Mark as visited. */
f->next = Cudd_Not(f->next);
return;
} /* end of zddSupportStep */
/**Function********************************************************************
Synopsis [Performs a DFS from f, clearing the LSB of the next
pointers.]
Description []
SideEffects [None]
SeeAlso [zddSupportStep]
******************************************************************************/
static void
zddClearFlag(
DdNode * f)
{
if (!Cudd_IsComplement(f->next)) {
return;
}
/* Clear visited flag. */
f->next = Cudd_Regular(f->next);
if (cuddIsConstant(f)) {
return;
}
zddClearFlag(cuddT(f));
zddClearFlag(Cudd_Regular(cuddE(f)));
return;
} /* end of zddClearFlag */
BRiAl-1.2.0/cudd/r7x8.1.mat 0000664 0000000 0000000 00000000474 13173454145 0015050 0 ustar 00root root 0000000 0000000 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
BRiAl-1.2.0/cudd/testcudd.c 0000664 0000000 0000000 00000077503 13173454145 0015370 0 ustar 00root root 0000000 0000000 /**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 [Copyright (c) 1995-2012, Regents of the University of Colorado
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the University of Colorado nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.]
******************************************************************************/
#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.23 2012/02/05 05:30:29 fabio Exp $";
#endif
static const char *onames[] = { "C", "M" }; /* names of functions to be dumped */
/**AutomaticStart*************************************************************/
/*---------------------------------------------------------------------------*/
/* Static function prototypes */
/*---------------------------------------------------------------------------*/
static void usage (char * prog);
static FILE *open_file (char *filename, const char *mode);
static int testIterators (DdManager *dd, DdNode *M, DdNode *C, int pr);
static int testXor (DdManager *dd, DdNode *f, int pr, int nvars);
static int testHamming (DdManager *dd, DdNode *f, int pr);
static int testWalsh (DdManager *dd, int N, int cmu, int approach, int pr);
static int testSupport(DdManager *dd, DdNode *f, DdNode *g, int pr);
/**AutomaticEnd***************************************************************/
/**Function********************************************************************
Synopsis [Main function for testcudd.]
Description []
SideEffects [None]
SeeAlso []
******************************************************************************/
int
main(int argc, char * const *argv)
{
FILE *fp; /* pointer to input file */
char *file = (char *) ""; /* input file name */
FILE *dfp = NULL; /* pointer to dump file */
FILE *savefp = NULL;/* pointer to save current manager's stdout setting */
char *dfile; /* file for DD dump */
DdNode *dfunc[2]; /* addresses of the functions to be dumped */
DdManager *dd; /* pointer to DD manager */
DdNode *one; /* fast access to constant function */
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 */
unsigned long startTime; /* initial time */
unsigned 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 = 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(optarg);
break;
case 'X':
maxMemory = atoi(optarg);
break;
case 'a':
approach = atoi(optarg);
break;
case 'b':
blifOrDot = 1; /* blif format */
break;
case 'c':
clearcache = 1;
break;
case 'd':
dfile = optarg;
break;
case 'g':
groupcheck = atoi(optarg);
break;
case 'k':
keepperm = 1;
break;
case 'm':
multiple = 1;
break;
case 'n':
N = atoi(optarg);
break;
case 'p':
pr = atoi(optarg);
break;
case 'v':
nvars = atoi(optarg);
break;
case 'x':
cacheSize = atoi(optarg);
break;
case 'h':
default:
usage(argv[0]);
break;
}
}
if (argc - optind == 0) {
file = (char *) "-";
} else if (argc - optind == 1) {
file = argv[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);
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);
if (pr > 0)
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);
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);
}
/* Test inequality generator. */
{
int Nmin = ddMin(nx,ny);
int q;
DdGen *gen;
int *cube;
DdNode *f = Cudd_Inequality(dd,Nmin,2,xvars,yvars);
if (f == NULL) exit(2);
Cudd_Ref(f);
if (pr>0) {
(void) printf(":4: ineq");
Cudd_PrintDebug(dd,f,nx+ny,pr);
if (pr>1) {
Cudd_ForeachPrime(dd,Cudd_Not(f),Cudd_Not(f),gen,cube) {
for (q = 0; q < dd->size; q++) {
switch (cube[q]) {
case 0:
(void) printf("1");
break;
case 1:
(void) printf("0");
break;
case 2:
(void) printf("-");
break;
default:
(void) printf("?");
}
}
(void) printf(" 1\n");
}
(void) printf("\n");
}
}
Cudd_IterDerefBdd(dd, f);
}
FREE(xvars); FREE(yvars);
Cudd_RecursiveDeref(dd, CP);
/* 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);
/* Experiment with support functions. */
if (!testSupport(dd,M,ycube,pr)) {
exit(2);
}
Cudd_RecursiveDeref(dd, ycube);
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